-
Notifications
You must be signed in to change notification settings - Fork 2
Paging Library
Devrath edited this page Jun 20, 2021
·
50 revisions
- Our world has become overloaded with data.
- data include things like
news feed,video,musicand more... - When things keep increasing we need to keep in mind not to overload the device itself because the device has limited number of resources.
- Phone has a very limited amount of real estate available to show the data that is available.
- On this limited amount of real estate, displaying the data in an efficient manner was solved by the usage of the
view holder patternin android. - Instead of created
n-viewsforn-numberof data, using the recycler view we could create few views forn-numberof data and recycle the views as we scroll along. - We can see how this is done in the diagram above.
- The view sure is recycled and helps in smooth scrolling but the data set is still large this can be handled efficiently.
- But still the data is in memory say a
list. If the data set increases to tens and thousands of items, we may run into performance issues. - This performance issue is for sure in older android devices.
- Paging library helps in fixing this issue in the
data sideby displaying only the data needed currently on the screen display. - What
view holderdoes on theview side, the paging does on the data side - Paging library doesn't keep all the data in the memory at once - > Paging library pulls the data from the data source on an as-needed basis.
- Paging library is designed to particularly operate well on
live dataandroom database
Paging element |
Description |
|---|---|
Data Source |
Determines where data comes from, like if it is room database or a network
|
PageList |
It is like a window to the list of items |
PageList Adapter |
It is a subclass of recycler view, that is used to show paged list in recycler views |
Data source type |
Description |
|---|---|
Page Keyed Data Source |
It gives paged items at a time |
Item Keyed Data Source |
It gives items one by one |
Positional Data Source |
Any number of items from any position |
- We need to keep track of keys so that we can retrieve the next and previous pages.
- We need to request the correct next page when the user scrolls at the end of the recycler view.
- We need to prevent duplicate requests.
- Paging library takes care of all the three points in the issues mentioned.
- Paging keeps track of the loading state, and if there is an error in loading, we can show a view with retry view.
- Refreshing of the list is also just a method call involved.
- We can transform the data using the list transformations using operators like
filter,mapetc which can befloworrx-java. - Adding the list separators is also very much easier.
- Data source is a single source of data - it's the single source of truth.
- If you are loading the data from a single source, Be it from
file-system,remote-source,local-database, we implement thepaging source - If we are using the room, it implements the paging source to help you.
- If you are fetching the data from the server and storing it locally finally displaying the data to the end-user, We use
remote-mediatorthat handles the data from the server and maintains a cached local state.
- To use the paging source we need to extend the
PagingSourceclass and override theloadmethod which is asuspendfunction. - Since this is a suspend function, we can use other suspend functions inside this like getting data from
local database,remote-api, etc. - Here we can pass the
prev-page,next-pagekeys received from the server. - If we don't receive the keys and the
APIisindex-based, we just use calculate it here. - Here we return
dataalong with keys wrapped inload-result, And we return theerrorif there is an error occurred. - Because of this when you build a network request, the keys are provided.
- Many times when we need offline support for data once it is retrieved from the server. We call it a
layered data sourcewhich is a combination ofnetworkandlocal data source. - Using the paging this works great together, with fresh data always from the server and sync data retrieved from the local database.
- This also offers offline support.
- Without the paging, it's hard to achieve and prone to bugs.
- Challenges faced include things like using the connected state is very hard since individual requests can
succeedorfail. - Also here we always request data from the network even if the data is available in the cache.
- So a better solution is always considering the
databaseas thesource of truthand get the data from the database and onfirst loador when the database is exhausted as represented below.
- As mentioned above if we are using just
roomthepaging sourceis provided by room byout-of-the-box
@Query("SELECT * FROM Movie ORDER BY ranking")
fun allMovies(): DataSource.Factory<Int, Movie>- If we are using
roomand a network data source we need to use theremote-mediatorclass - We need to use a class that uses
remote-mediatorclass - Once we do that we need to over-ride the
load-method. - This
load-methodwill be triggered when we require new data. - The
load-methodis asuspendfunction. meaning we can call other suspend functions in it. - Using the
service classreference from the constructor, we can store it in the database. - In the mediator class, we need to tell the paging if there is more data or not in the API.
val isEndOfThePageAchieved = dataFromApi.isEmpty()
return MediatorResult.Success(isEndOfThePageAchieved)If there is some error or exception, we return the error using
val isEndOfThePageAchieved = dataFromApi.isEmpty()
return MediatorResult.Error(exception)-
Pager-> This is the primary entry point for the pager - We construct the paging using the
configurationand thedata sourcethat makes the pager
When the API is the source of truth
Pager(
PagingConfig(pageSize=30)
){
CustomPagingSource(apiService)
}When we are using a database and API, we consider the database as the source of truth
In this case we need to pass a remote mediator also along with the config to the paging constructor
val sourceOfPaging = databaseService.Dao.List
Pager(
PagingConfig(pageSize=30)
RemoteMediator(databaseService,remoteService)
){
sourceOfPaging
}Difference you can note in both the above types is as explained in earlier concepts mediator manages the part of handling the caching part, once the data is changed in the database the observers in the UI will be notified
PagingConfig(
pageSize = 30,
prefetchDistance = 30,
enablePlaceHolders = true,
initialLoadSize = 30*3,
maxSize = PagingConfig.MAX_SIZE_UNBOUNDED
jumpThreshold = 0
)The Pager returns the flow/observable/flowable/livedata depending on whether we are using coroutines or rxjava this can be used by the UI to display the dat to the end user
- For this purpose we implement
paging data adapter - This
paging data adapterextends the regular RecyclerView adapter and provides all the functionalities ofrecycler viewand in addition, it provides ways to handle paging data. - In the constructor of the Paging data adapter we can even pass diffUitl utility for smoothness to handle abruptness found when an item is removed and
notifydatasetchange()is applied. - We have a
coroutine flowin the view thatcollectsthe data from the view model and submits it to thepager adapter.
- Since having a header and footer is not part of the actual
recycler-viewlist, paging provides a new adapter for this calledLoadStateAdapter - This adapter will be seperate for both header and footer
- Basically if we have
header,footer, andlist-> We have three adapters for ourrecycler-viewlist. - We set all the adapters like mentioned below.
private fun setupViews() {
binding.apply {
// Adapter: List of items
rvPosts.adapter = adapter
// Adapters: Header and Footer item
rvPosts.adapter = adapter.withLoadStateHeaderAndFooter(
// Header
header = RemoteApiLoadingAdapter { adapter.retry() },
// Footer
footer = RemoteApiLoadingAdapter { adapter.retry() }
)
}
}- One additional feature useful is the ability to transform the data before it is displayed in the
recycler-view. - Before it's published we can use
map,filterto modify and pass the data to therecycler-view. - If we are handling the configuration changes, the
transformationscan be expensive so after the transformations are done and just before publishing data we usecachedinso that data can be reused in adapter instead of applying the transformations again.
