How to build pagination in RecyclerViews

API endpoints that return a list of data often have pagination parameters that you can pass in to get different pages of lists back. Often, they have something like page and per_page parameters that you can pass in.

Let’s say that there’s an API endpoint that returns a list of books. In the database of the API, there are 100,000 books. It would be impractical to fetch all 100,000 books from the API all in one request. In fact, we would probably get an OutOfMemory exception. To avoid this, we want to paginate through our list of books when making requests to our API. Just as a note, the code samples below for making the API calls are using Retrofit with GSON.

Setting up Retrofit for pagination

Here’s our Retrofit interface with a definition that will get a list of books with pagination

Here, the page is referring to the page number that you want and limit is referring to the number of books you would like to fetch per page.

I generally like to have an interface where I define variables that will be constants throughout my application. Page limit for pagination purposes when making a API request is one of those things that I like to keep consistent throughout my apps, unless it’s a requirement that they be different throughout the app. So let’s make a Constants interface.

Here’s I have set up a Constants interface that I can implement throughout my activities and fragments. I also defined a URL_DOMAIN that would be consistent throughout the app.

Now, let’s write our class that will generate our RetrofitService.

This ServiceGenerator just has a factory method that will generate our service whenever we need it.

Making the API call

We’ll be making the API requests in our MainActivity. Let’s also say that we have already defined our activity_main.xml with a RecyclerView and that we have our layout for our row adapters for our RecyclerView all set and ready to go.

Building the pagination

We’ll be using a library for this portion. There are two main reasons for this.

  1. It makes for shorter, more readable, and concise code
  2. It comes with Material Design loader all ready and set to go
  3. Most guides that shows you how to do this manually don’t work very well

The biggest reason is number 3. If you do a quick Google search on how to paginate through a RecyclerView, you’ll quickly realize that there isn’t really a consensus on how to do this properly. Also, there isn’t really a clean API on the RecyclerView that allows you to detect the exact position of the user in your RecyclerView. Just to figure out where your user is, you have to do all sorts of positioning math wizardry, which can take time to figure out and can be easy to get wrong. Thus, to make our lives easier, we use a library.

The one that I found to be the simplest and straightforward to use is the Paginate library by MarkoMilos (https://github.com/MarkoMilos/Paginate). So add that to your app/build.gradle file and also add the SmoothProgressBar (https://github.com/castorflex/SmoothProgressBar) to it too. The SmoothProgressBar is actually already a dependency of the Paginate library, but in case you want to customize your loader spinner that the user sees when he/she reaches the bottom of the page, you’ll need that SmoothProgressBar library added separately to your app/build.gradle file.

Finally, let’s set up our pagination!

A few things have been added and changed in this final version.

First major thing is that we have added the overriding callbacks that are required by the Paginate library. As for the instance variables, we have added three:

  1. Boolean variable mLoading which is initialized to false and
  2. Integer variable mCurrentPage which is initialized to 1
  3. BookLibraryServiceAPI mService so that we can initialize it just once and reuse throughout the MainActivity class
  4. There is a new variable mPaginate that will initialize the pagination feature.

The mLoading variable is set to true when we’re making the API call, but is set back to false when the API call has finished. We then use this variable in the overridden isLoading() method to tell our Paginate library whether new list is being loaded into our RecyclerView or not.

The mCurrentPage variable is incremented by 1 in the onLoadMore() method so that whenever we are loading a new set of books, we are retrieving the next page.

When we piece all of this together, you’ll see the beautiful pagination working whenever the user scrolls down.

A couple of notes on the mPaginate build method and its chained methods and parameters (the important parts).

  • In the Paginate.with(), you pass in the RecyclerView that you are paginating by
  • The setLoadingTriggerThreshold is the number of items that are left in the RecyclerView from the bottom of the list while the user is scrolling that should trigger the next API request. In my example, I have set this to 10. So, as the user scrolls, as soon as there are 10 items left in the RecyclerView, the next API request (if there are any more pages left) will be made.

And that’s it! This should allow you to build in smooth pagination features in your apps.

About the Author Chris Jeon

Software developer currently focusing on Android development.