Paging library has a different type of DataSources for the different use case. You can have a
, and a
PageKaydDataSource.In this tutorial, we discussed different use case of DataSource and how they load initial data, next page and reload data when data invalidate.
If you have an application like Contacts application on Android, where you have the data locally, but the user may want to jump into arbitrary positions,
PositionalDataSource is your best option. This is actually what Room uses behind the scenes.
If you have a DataSource or UI like that, You extend this PositionalDataSource class, and you specify the type of items.
public class MyDataSource extends PositionalDataSource<User>
To better understand how this DataSource behaves, let’s look at an example. The very first time you come to the RecycleView, PagedList will call this
loadInitial method on the DataSource, pass the start position, page size, and initial load size, which is usually larger than the page size, because you want to have more items at the beginning and whether placeholders are enabled or not. In this example,we just assume placeholder are enabled.
Our DataSource return the data and tell us where that data starts, and it will give us the total number of items in the DataSource. Based on that, we’ll start displaying the data, but we’ll also display the placeholder that is the size of the total number of items in the DataSource.
As soon as the user starts scrolling, pages will realize that it’s going to run out of data, and it’s going to call this
loadRange method on the
PositionalDataSource, pass the start position of the first item that’s missing and the page size, and get the new data appended to the list.
The user uses the fast scroller and jumps into an arbitrary position where we didn’t have the data yet. When this happens, it won’t call the DataSource
loadRange position. We take positions slight level RecyclerView and load that page so that we can display it to the user. This is why
PositionalDataSource is really good if the user can jump into arbitrary positions. You never block them.
Let’s say something has happened in the database. Data has been invalidated. So we ‘ll get a new DataSource. Each DataSource represent a snapshot of the data. So we get this new one. It’ll create the new pages for it, and It’ll load the initial page from this DataSource based on where the user is in the previous one. It’ll bring this one as always on a background thread. It will calculate the difference between these two lists and update the RecyclerView with the correct animations.
Imagine you have some data, like a list of names. If you look at the page out of this, you could identify the items before this page by using the first item in the list and the next page by using the last item in the list. Basically, every item can identify a page after or before it.
If your DataSource is like that, you should implement the
ItemKeyedDataSource class. You provide a key type in this case we are using names, it is String and the item type in the list.
public class MyDataSource extends ItemKeyedDataSource<String, Item>
The first time you come to the RecyclerView, it called the
loadInitial method, passed the initial key, which is null, because we don’t have it. It requests the load size and whether placeholder is enabled or not. We’ll just assume they’re not enabled in this example.DataSource will only return this data. It’s not going to count it because there’s no placeholder. 2222222
As soon as user start scrolling, we will extract the key from the last line that we have and then call the DataSoure
loadAfter method to load other page. Similarly keeps scrolling, just extracts a key, and then loads another pagethe same way.
Now at this point, let’s say this data was coming from the database and something has changed, so we lost the DataSource. It’s been invalidated. We’ll get a new DataSource.When we create a new PageList for this DataSource, we are going to extract the key from one of the items that is currently visible in the RecyclerView closer to the top and load a page from this new DataSource. It will calculate the difference and update the UI with the correct animations.
If the user tries to scroll up, we need more data. The same thing-you just extract the key from the first item, call loadBefore method on the DataSource, get that page, append it to the PagedList, and now user can scroll outwards. So it’s a way lazy, always reactive.
This is a really common way of paging, especially on the server side APIs.Your client sends a request, and when the response comes from the server, it includes the data. It also includes pointers for the next and previous keys.GitHub and Reddit API work this way. It’s very common.
So if you have a DataSource like that, you should implement the
PagedKeyedDataSource specify the type of keys that you use in the pointers and the item type.
public class MyDataSource extends PageKeyedDataSource<String, Item>
The first time a user comes to the UI. We call
loadInitial. We give it a size and whether placeholders is enabled or not. They’re usually disable because your server doesn’t give you an accurate count. Then the DataSource returns data, but it also gives us pointers for the previous key and the next page key. Now, we start displaying it.
If the user scrolls, we need more content. So we are going to call the
loadAfter method, use the key that was returned in the previous request to get the next page from the DataSource. Now, this next page comes with a field called adjustmentPageKey, it always tells, ok what is the next page in this direction? It’s literally like a linked list of pages. Once you take that, the user can scroll more.
Now, a difference in this DataSource is how we handle invalidation. Imagine user hit the refresh button on the screen.DataSource is invalidated.we’ll get a new DataSource, but in the
loadInitial method, there is no key anymore. This is because it is a linked list. If the previous list is invalid, links in the list don’t mean anything. So you always need to load the very first page again and display it in the UI. This is usually not a problem in practice because you only do this if a user does swipe to refresh, so they are already on the top of the list.