Android paging library with RxJava and REST API

Ahmed Abdelmeged
5 min readFeb 21, 2018

--

Recently I was working on news application and normally it’s a paged news. I request news based on last item Id and this a very common thing on android. But implementing this maybe by tricky with all of this RecyclerView scroll listener, error and refresh handling you start to lose control on your code and things start to become missy. I saw the announcement of the paging library which is part of the android architecture component and the awesome talk by Florina Muntenescu. You should definitely watch it. So i started to play around with it. It’s alpha so the API changes and it’s not recommended to add it in production. Let’s see what paging offering to you out of the box. It’s forces you to make you loading data abstracted from the UI code, It handles all the adapter changes and validation for you and more awesome stuff. Most of the examples out three showing it working with room and it’s not the case for most developers so i decided to make sample with REST API and RxJava Yeah! of course it can work without it but my application use RxJava a lot. The sample app will use GitHub API to fetch list of users. You can say it’s very simple example no need for Rx here but most of the applications including mine use a lot of Rx power and after doing some operations on the data i want to deliver the final result to the paging and it will handle the rest. It’s just sample example how to integrate Rx with the paging library can be found at this Repository in Kotlin and Java So no use of design patterns , dependency injection and all this fancy stuff for a complete example check this Repository. Now let’s see step by step how to integrate it. Enough talk let’s get now some theory about paging and how it’s work

Prerequisites

I assume you already familiar with RxJava and architecture component (Live data and view model) if not it’s a great time to start there are a lot of good references out there , here and here

Paging Library Components

The main component of paging library are DataSource, PagedList and PagedListAdapter

DataSource

This a component responsible for loading the data. Depending on how you need to access your data, you would extend one of its subclasses. At our use case we load the next page by know the last element id after reading the docs sound convenient to use ItemKeyedDataSource for more details and other subclass check the docs

PagedList

This a A wrapper list that holds your data and tell the data source when to load data . You can configure how much data is loaded at a time, and how much data should be prefetched. It’s provides updates to the adapter as the data loaded in pages

PagedListAdapter

This class is implementation of RecyclerView.adapter that presents data from PagedList and take DiffUtil as parameter to calculate the difference in the data and do all the updating work for you

Hot it work

Let’s consider we have REST API here when the data come from DataSource on a background thread. It will update the PagedList value,The PagedList notifies its observers of the new list on the mainThread. Now the PagedListAdapter will receive the new list. On the background thread will compute the changes using DiffUtils and back with the result on the mainThread then call onBindViewHolder with updated data to update the view

Sample App

Enough theory let’s gets our hands dirty and start coding

Add dependencies

//Architecture Components
implementation "android.arch.lifecycle:extensions:1.1.0"

//Paging
implementation "android.arch.paging:runtime:1.0.0-alpha5"

//Networking
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

//Rx
implementation 'io.reactivex.rxjava2:rxjava:2.1.9'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'

Service

DataSource

Now to the fun stuff. As i said earlier. I extended the ItemKeyedDataSource which a subclass and you need to implements it’s four methods in the code below i hide all the retry and error so it’s brief for the full code check UserDataSource.kt

The first method is loadInitial which is first method get called when the DataSource initialized to load the first set of data then the loadBefore called to get some data before the id but at this sample we won’t implement it. loadAfter called every time when the PagedList said hey i need new data. The forth one id getKey and here you provide the key needed to load the next page in our case it’s the user id.

Note

You maybe wonder why i don’t use one of Rx most powerful features which specify the threads i want to work in or observe on. I already try this but it give strange behavior after some analysis i realize that the load methods called on background thread provided by Paging. The problem is you get the data on thread and load methods called on another thread.

You will realize also in the sample that i’m using LiveData to push the network updates to the UI of course we can use Rx publisher for that but it will get complicated. Put your Rx code in the data layer and on the UI layer use LiveData because it’s lifecycle aware and will handle the subscription and realizing for you.

DataSourceFactory

This responsible for creating the DataSource so we can give it to the PagedList

ViewModel

The view model will responsible for creating the PagedList and give to the activity so it’s can observe the data changes and pass it to the adapter. The full code UsersViewModel.kt

PagedListAdapter

The adapter here have two view types the user and the network state and you need to path a DiffCallback to it’s constructor. The full code UserAdapter.kt

Activity

After all of this you will see that the activity code is now very simple and it’s very easy to handle it’s lifecycle and configuration change. The full code MainActivity.kt

We are done!

Conclusion

As you see adding paging functionality to your app with paging library makes it’s easier and add an abstract layer between your UI logic and data logic so it’s clean and can be tested. Let us wait for it to become stable so we can add it in production. If you have a better idea or another opinion just post a response or keep in touch with me

Twitter:A_K_Abd_Elmeged

Github: Ahmed-Abdelmeged

--

--

Ahmed Abdelmeged

Senior Android Engineer @N26. Co-founder & Mentor @eg_droid