Android RecyclerView Pagination with Paging Library using MVVM, RxJava, Dagger 2 and LiveData

MOHD SAQUIB
MindOrks
Published in
9 min readSep 13, 2018

At Google I/O this year we saw the introduction of Paging Library, a part of Android Jetpack and an Architecture Component to load data in an efficient way within your app’s RecyclerView. While consuming REST API if we are getting data on a large scale but we want to show data in a portion at a time when we will go for pagination logic. Before Paging Library we usually used to handle pagination using onScrollListner etc. in RecyclerView but to implement this we include much more logic for paging data and displaying lists, to notify our RecyclerView. To get rid of all these hectic logic what we always used to keep in mind while developing app a new concept introduced by Google and i.e. Paging Library.

Several advantages of using Paging Library are:
1. Data requests consume less network bandwidth and fewer system resources. Users who have metered or small data plans appreciate such data-conscious apps.
2. Even during data updates and refreshes, the app continues to respond quickly to user input.

Working of Paging Library

Paging Library Components

Paging library consists of three main component and these are…

DataSource

Datasource is the base class for loading data. There is the various way to load data into your list, you can use it by extending any one of its 3 subclasses and these are…

PageKeyedDataSource
If you want to load data based on the page number in the DataSource than you can use PageKeyedDataSource. We will have to increment page number sequentially until all pages loaded successfully.

ItemKeyedDataSource
This type of DataSource used where you need to load data of a page which required data from the previous page. For example, suppose you want to load chat data of element N and you need chat_id of element N-1.

PositionalDataSource
It will be useful for sources that provide a fixed size list that can be fetched with arbitrary positions and sizes means use PositionalDataSource if you are loading pages of a requested size at arbitrary positions, and provide a fixed item count.

PagedList

PagedList is a wrapper list that holds your data items and tells the DataSource when to load the elements or you can say it is a list which loads its data in chunks (pages) from a DataSource. Items can be accessed with get(int) and further loading can be triggered with loadAround(int). To display data from PagedList we will use PagedListAdapter.
Creating PagedList loads the first chunk of data from the DataSource immediately, and should, for this reason, loading be done on a background thread.
PagedList.Config is used to control when and how many items PagedList loads.

PagedListAdapter

This class is responsible for presenting data loaded by PagedList and it is the implementation of RecyclerView.adapter. It uses DiffUtil as a parameter to calculate data differences and do all the updates for you.
when a new page is loaded, the PagedListAdapter signals the RecyclerView that the new data has arrived, this lets the RecyclerView replace any placeholders with the actual items.

These were the basic concept about the component of Paging Libary. Let’s start with coding part how to use these in the real world. I will use MVVM, RxJava, LiveData and Dagger in sample app for Paging Library implementation if you are not aware of these concept then you are requested to refer to my previous article (link is mentioned below) which will be very useful for understanding how to use MVVM , RxJava, LiveData, Dagger with Rest Api call using Retrofit.

Let’s start code, I will fetch article from news API and show you just title and image of each news article, have a quick look of the app’s Gradle.

To implement Paging Library first we add a dependency in our app’s gradle file.

implementation 'android.arch.paging:runtime:1.0.1'

Here in gradle file, you can see I used multiple dependencies for different library and I also enabled dataBinding to true for implementing binding in my adapter class. To learn about data-binding in deep refer to this link. I will just show you its implementation.
Now move further in code, first of all let me show you a few important classes before moving DataSource/PagedListAdapter class implementation.

public class Repository {    private ApiCallInterface apiCallInterface;    public Repository(ApiCallInterface apiCallInterface) {
this.apiCallInterface = apiCallInterface;
}
/*
* method to call news api
* */
public Observable<JsonElement> executeNewsApi(int index) {
return apiCallInterface.fetchListNews(Constant.sources[index], String.valueOf(Constant.API_KEY));
}
}

This is repository class where we just write methods for fetching articles.

public interface ApiCallInterface {    @GET(Urls.FetchNewsList)
Observable<JsonElement> fetchListNews(
@Query("source") String source,
@Query("apiKey") String apiKey);
}

This is ApiCallInterface where we used Retrofit to hit API.

public class Urls {
public static final String BASE_URL = "https://newsapi.org/v1/";//put your base url here
public static final String FetchNewsList = "articles";//put your end point here}

In Urls class, we just added the required URL for fetching news articles.

public class Constant {    public final static String LOADING = "Loading";
public final static String LOADED = "Loaded";
public final static String CHECK_NETWORK_ERROR = "Check your network connection.";
public final static String API_KEY = "...";
public static final String sources[] = {"bbc-news", "abc-news-au", "bloomberg", "cnbc"}; public static boolean checkInternetConnection(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
return false;
} else {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (NetworkInfo anInfo : info) {
if (anInfo.getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
}

In Constant class the most important thing is the API_KEY, you will have to generate your own API_KEY to fetch the news articles. Please go to this link and generate your API_KEY by clicking on Get API Key and use it. I used sources[] to just fetch news article from 4 to 5 sources you can change it but there is no need to change it to just test it.

( UtilsModule.java )

Look at UtilsModule.java, I used this class for injecting objects, that means you create the object once and reuse it throughout your application where required and by just inject that object, there is a lot of way of dependency injection but here we will use Dagger API.

I used here dagger:2.13 for dependency injection, you can learn more from this article about dagger.

You have to create a module class using annotation @Module which will create objects by using @Provides and @Singleton annotation. I created here few objects those are needed for this project. For instance, to consuming rest API you need to have the retrofit object so I create here Retrofit object and we will inject it wherever it needed like “@Inject Retrofit retrofit”.

Let’s come on the DataSource and PageListAdapter classes. Since we have to fetch news article from API and loading 10 records in a single page and increment page number sequentially. To achieve this we simply use PageKeyedDataSource as I discussed earlier when to use which one of the three subclasses of DataSource.

Before implementing PageKeyedDataSource we write the implementation of DataSource.Factory class which will interact with ViewModel directly and provides the response using LiveData.Let’s see code implementation…

( NewsDataSourceFactory.java)

DataSourceFactory is responsible for retrieving the data using the DataSource and PagedList configuration which we will create later in this article in our ViewModel class.

Now have a look at DataSource implementation.

( NewsDataSourceClass.java)

The following code shows how we can create PageKeyedDataSource for our NewsDataSourceClass class to fetch news article.
When we extend PageKeyedDataSource, there will be three method override i.e. loadInitial(LoadInitialParams,LoadInitialCallback), loadBefore(LoadParams, LoadCallback) and loadAfter(LoadParams,LoadCallback). First DataSource class will execute loadBefore(…) method and just after method loadInitial(…) will execute. We fetched news initially in loadInitial(…) on passing start page number (i.e. 1) as you can see in code. It has a callback.onResult will produce data to add in PagedList.
Callback for loadInitial(LoadInitialParams,LoadInitialCallback) to return data and, optionally, position/count information. A callback can be called only once and will throw if called again.
If you can compute the number of items in the data set before and after the loaded range, call the three parameter onResult(List, int, int) to pass that information.

It is always valid for a DataSource loading method that takes a callback to stash the callback and call it later. This enables DataSources to be fully asynchronous, and to handle temporary, recoverable error states (such as a network error that can be retired).

Let’s come on ViewModel implementation.

( PagingLibViewModel.java)

In our ViewModel class, we used the PagedList.Config i.e.

PagedList.Config pagedListConfig =
new PagedList.Config.Builder()
.setEnablePlaceholders(true)
.setInitialLoadSizeHint(10)
.setPageSize(10).build();

Here we are loading just 4 pages and each page containing 10 records. PagedList’s Builder class contain few important methods and they are used while building PagedList.Config. It Configures how a PagedList loads content from its DataSource.

We used .setEnablePlaceholders(true) which show enablePlaceholders it means there is a placeholder that is visible to the user until the data is fully loaded. So for instance, if we have 10 items that are needed to be loaded and each item contains an image when we scroll through the screen, we can see placeholders instead of the image since it is not fully loaded.
We used .setInitialLoadSizeHint(10) that shows size hint for the initial load of PagedList, often larger than a regular page.in our case, it is 10.
The last method we used is .setPageSize(10) that means the number of items to load in the PagedList or size of each page loaded by the PagedList.

After configures a PagedList now time to build it with DataSource.Factory using LivePagedListBuilder. It creates a LivePagedListBuilder with required parameters i.e. DataSource.Factory and a PagedList.Config . build() method of LivePagedListBuilder will constructs the LiveData<PagedList> and we will observe constructed LiveData<PagedList> in our activity. If you will look in above code implementation you will see a listLiveData object of type LiveData<PagedList<NewsModelClass>> is used to achieve this and it is being observed in our activity.

There is another LiveData<String> progressLoadStatus, we are using it to show progress status in our UI. And its implementation is …

progressLoadStatus = Transformations.switchMap(newsDataSourceFactory.getMutableLiveData(), NewsDataSourceClass::getProgressLiveStatus);

We used here Transformations.switchMap it is basically transformations for a LiveData class. You can use transformation methods to carry information across the observer’s lifecycle. The transformations aren’t calculated unless an observer is observing the returned LiveData object.
Because the transformations are calculated lazily, the lifecycle-related behavior is implicitly passed down without requiring additional explicit calls or dependencies.

In our code implementation we show you in NewsDataSourceClass that we used a livedata object to just put the status of loading data and that we are observing in our UI by using switchmap in ViewModel which indicates that whenever livedata of NewsDataSourceFactory class will change it will fetch current status of progress and put into progressLoadStatus which will be observed in activity. I will show you activity code implementation than it will be more clear.

Now move further in our Activity code implementation. Below is the Activity class implemented for this project.

( PagingDemoAct.java)

In PagingDemoAct we are observing LiveData and submitting it to the adapter by using a submitList method which is part of PagedListAdapter, and we are also observing progress status for loading chunk of data for a page.

Now have a look of our adapter class.

( MyPageListAdapter.java)

Here I am extending PagedListAdapter<NewsModelClass, MyPageListAdapter.MyViewHolder> as I discussed at the beginning of this blog that to implement paging library I will use PagedListAdapter. In adapter class, I am setting just image and title of the article.
PagedListAdapter is an implementation of RecyclerView.Adapter that presents data from a PagedList. It uses DiffUtil as a parameter to calculate data differences and do all the updates for you.

The DiffUtil is defined in the new model class Class in my sample app scenario, see its code implementation…

( NewsModelClass.java)

I am just comparing the title of the article to differentiate news article. One more thing that I used the data-binding library to bind data to UI.
You can refer to this article to know more about data-binding.

As I am not mentioning my API_KEY in sample project, so please go to this link and generate your API_KEY by clicking on Get API Key and use it by putting it into Constant class.

That was all about this article, give a clap if you like the article. You can refer to more article for reference.

  1. https://developer.android.com/topic/libraries/architecture/paging/
  2. https://developer.android.com/jetpack/

Do find the full source code from here:

Let’s become friends on Linkedin and Facebook.

Happy Coding…
Thanks & Regards

--

--