Pagination Android Tutorial: Getting Started

Pagination (Endless Scrolling or Infinite Scrolling) is a feature common in content-heavy apps. It breaks down a list of content into equal smaller pieces, loaded one at a time.

This is the first post in a series of Pagination articles. The series covers how to implement Pagination with RecyclerView, handle adapter changes with new data, error handling and more.

Pagination Series Overview

  1. Pagination Android Tutorial: Getting Started
  2. Using APIs with Retrofit and Gson
  3. Error Handling
  4. Using Multiple RecyclerView Types (coming soon)
  5. Adding Swipe-to-Refresh Support (coming soon)

What, Why and When of Pagination

Pagination is the process of dividing a document into discrete pages, either electronic pages or printed pages. –  Wikipedia

Already know what Pagination is? Jump straight to the code section!

What we’re going to do, relates to this definition. Loading the next set of data (next page), by specifying its index (page number).

What is Pagination?

Users of Facebook, Twitter or Instagram will know what I’m talking about. After all, we’ve spent countless hours scrolling through them haven’t we? aThey just don’t seem to end!

twitter profile tweets pagination endless scroll load more

Twitter Profile Tweets list

Why Pagination?

From a developer’s perspective, how would you load all of that content? It is not possible to make a call for such huge content at one go. We’ll have to request them in parts, or ‘pages’.

Pagination allows the user to see the latest content with little wait time. As we load the next ‘page’ by the time users scroll to the bottom, more content is loaded and available.

When to use Pagination?

I’m sure you have a pretty good idea by now on when to use it. If you have a ton of content that takes too long to load. This can be either from a local database or an API call. Then it makes sense to use Pagination. If you’re pulling from a database, request data in batches (say 20 per request). The same also holds true for an API call.

Good APIs that deal with a ton of content, do provide Pagination support.

With that out of the way, I’m sure you’d want to see some Android code with Pagination in action. So without further delay, let’s get straight to it!

Getting Started

As we all know, Pagination has been around for quite some time. This opens it up to various approaches on how exactly to do it.

Here are some solutions you might have come across:

But these don’t tell you how to show or hide a footer loading progress (ProgressBar). You also would have resorted to an Android Pagination library on GitHub:

Usually I’d suggest one of the above, but this time I won’t. That’s because we can roll our own scroll listener. This would be simpler instead. Sometimes its better to be in control of our feature, especially when third party solutions refuse to work the way you want.

Android Pagination with RecyclerView

Custom OnScrollListener

public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener {

    LinearLayoutManager layoutManager;

    public PaginationScrollListener(LinearLayoutManager layoutManager) {
        this.layoutManager = layoutManager;

    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        int visibleItemCount = layoutManager.getChildCount();
        int totalItemCount = layoutManager.getItemCount();
        int firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition();

        if (!isLoading() && !isLastPage()) {
            if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
                    && firstVisibleItemPosition >= 0) {

    protected abstract void loadMoreItems();

    public abstract int getTotalPageCount();

    public abstract boolean isLastPage();

    public abstract boolean isLoading();

Copy over this class. To enable Pagination, we must detect the user reaching the end of the list (RecyclerView). PaginationScrollListener allows us to do so.

The onScrolled() logic is the most important piece of your entire Pagination logic. So make sure you’re doing it right. The key snippet which contains the Pagination logic is as follows.

How to start an App Business in less than a week with zero app development. APPPortunity Coaching Program - Enroll now for an insane 98% discount!

if (!isLoading() && !isLastPage()) {
    if ((visibleItemCount + firstVisibleItemPosition) >= totalItemCount
                    && firstVisibleItemPosition >= 0) {

Layout Setup

Create a layout with RecyclerView and a ProgressBar (for indicating load of initial content).

// activity_main.xml skeleton layout

    < /> 
    <ProgressBar android:layout_gravity="center”/> 

Creating RecyclerView.Adapter

First, create class PaginationAdapter extending RecyclerView.Adapter, and then create two RecyclerView.ViewHolder.

  1. class ContentVH (main content item)
  2. class LoadingVH (footer ProgressBar used for Pagination)

I will be going through the essentials of the adapter, as creating a regular RecyclerView.Adapter is quite common by now.

public class PaginationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 // flag for footer ProgressBar (i.e. last item of list)
     private boolean isLoadingAdded = false;
     public int getItemCount() {
         return movies == null ? 0 : movies.size();
     public int getItemViewType(int position) {
         return (position == movies.size() - 1 && isLoadingAdded) ? LOADING : ITEM;

For our example, let’s assume we want to display a list of movies.

List<Movies> (your data) must reside in the RecyclerView.Adapter class only. You can access it via Getter Setters.
Adapter Helper Methods

Add the following methods to PaginationAdapter. They will be useful for added data fetched via Pagination.

public void add(Movie mc) {
    notifyItemInserted(movies.size() - 1);

public void addAll(List<Movie> mcList) {
    for (Movie mc : mcList) {

public void remove(Movie city) {
    int position = movies.indexOf(city);
    if (position > -1) {

public void clear() {
    isLoadingAdded = false;
    while (getItemCount() > 0) {

public boolean isEmpty() {
    return getItemCount() == 0;

public void addLoadingFooter() {
    isLoadingAdded = true;
    add(new Movie());

public void removeLoadingFooter() {
    isLoadingAdded = false;

    int position = movies.size() - 1;
    Movie item = getItem(position);

    if (item != null) {

public Movie getItem(int position) {
     return movies.get(position);

That is all for the adapter. Complete PaginationAdapter code is available here, just in case.

Preparing RecyclerView
// RecyclerView Adapter setup
PaginationAdapter adapter = new PaginationAdapter(this);
 linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
 rv.setItemAnimator(new DefaultItemAnimator());

Upon careful inspection, Pagination works in this flow:

  1. Display loading progress (ProgressDialog) on empty screen while fetching initial data
  2. Hide ProgressDialog and display data
  3. Detect user scroll to the end of list
  4. Show ProgressDialog at footer while fetching next page data
  5. Remove footer ProgressDialog and display fetched data
  6. Repeat Steps 3, 4 & 5 until all pages have loaded

Notice that the setup for certain steps are already in place. Loading initial data (page 0) will handle Step 1 and 2. PaginationListener will handle Step 3 and 6. PaginationAdapter helper methods will handle Step 4 and 5.

The following code setup will show you how all this will tie together.

Activity Setup

Here’s the entire It should give you a clear understanding of how everything ties together.

Be sure to note the variables here. As each plays a key part in the Pagination logic. Also, remember that TOTAL_PAGES will be determined by how many pages your API has. Usually, this will be included in the paginated response.

public class MainActivity extends AppCompatActivity {

    PaginationAdapter adapter;
    LinearLayoutManager linearLayoutManager;
    RecyclerView rv;
    ProgressBar progressBar;
    // Index from which pagination should start (0 is 1st page in our case)
    private static final int PAGE_START = 0;
    // Indicates if footer ProgressBar is shown (i.e. next page is loading)
    private boolean isLoading = false;
    // If current page is the last page (Pagination will stop after this page load)
    private boolean isLastPage = false;
    // total no. of pages to load. Initial load is page 0, after which 2 more pages will load.
   private int TOTAL_PAGES = 3;
    // indicates the current page which Pagination is fetching.
    private int currentPage = PAGE_START;

    protected void onCreate(Bundle savedInstanceState) {

        rv = (RecyclerView) findViewById(;
        progressBar = (ProgressBar) findViewById(;

        adapter = new PaginationAdapter(this);

        linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        rv.setItemAnimator(new DefaultItemAnimator());

        rv.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) {
            protected void loadMoreItems() {
                isLoading = true;
                currentPage += 1; //Increment page index to load the next one

            public int getTotalPageCount() {
                return TOTAL_PAGES;

            public boolean isLastPage() {
                return isLastPage;

            public boolean isLoading() {
                return isLoading;


 Loading Initial Data

Here’s how we’ll be using that method to perform the initial load (i.e. 1st page request):

private void loadFirstPage() {
    // fetching dummy data
    List<Movie> movies = Movie.createMovies(adapter.getItemCount());

    if (currentPage <= TOTAL_PAGES) adapter.addLoadingFooter();
    else isLastPage = true;

We can even mimic network delay, using a Handler.

// mocking 1 second network delay
new Handler().postDelayed(new Runnable() {
    public void run() {
}, 1000);

Once we load the initial request and get data, hide the ProgressBar. Next, the fetched data is added to the adapter and notified. The addAll() helper method in PaginationAdapter accomplishes this.

The initial data to be loaded is the 1st page (0th index). This must be a separate call, as the remaining pages are handled differently.

Using PaginationScrollListener

Notice how PaginationScrollListener uses our Activity defined flags. It needs the LayoutManager supplied to RecyclerView to count and compare the number of items it has. This is more accurate to know how many items are actually in layout, rather than counting the List<Model>. But for now, its constructor only supports LinearLayoutManager.

Startup Framework (Image)

Once initial data has loaded, its time to listen to scroll changes and trigger the next page 

private void loadNextPage() {
    List<Movie> movies = Movie.createMovies(adapter.getItemCount());  // 1

    adapter.removeLoadingFooter();  // 2
    isLoading = false;   // 3

    adapter.addAll(movies);   // 4

    if (currentPage != TOTAL_PAGES) adapter.addLoadingFooter();  // 5
    else isLastPage = true;

Now let’s look at the steps we take to load page 2. This remains the same for all pages beyond this.

  1. Get data (response) from API
  2. Remove footer ProgressBar to make way for new data
  3. Indicate that the next page is currently not loading (using isLoading)
  4. Add your new data to adapter
  5. Check if this is the last page. If not, add back the footer ProgressBar

Final Output

As per our code setup, we create 10 dummy content per page load. The number of times Pagination will happen is 3 (TOTAL_PAGE). Add that with the initial page load, and you’re looking at 40 items in total.

Go ahead and run the app.

Pagination result GIF

Pagination result GIF

Available on GitHub.
For Scroll listener, refer to this updated class – PaginationScrollListener.

We now have a working Android app with a RecyclerView that supports Pagination.

So how are you going to Paginate your apps? Do you think this approach is good? Or do you have something better in mind? Drop ’em in the comments below.

An App developer with an eye for design. Loves to create apps with good UI/ UX that people appreciate. In his spare time, he likes to draw and paint.

Recommended Android Books to Read


An App developer with an eye for design. Loves to create apps with good UI/ UX that people appreciate. In his spare time, he likes to draw and paint.

You may also like...

  • Pedro Joya

    Hi, @suleiman19:disqus, how do you manage orientation change? I mean, should I save the current state and data of the RecyclerView? If that’s the case, how does it affect your scrolllistener and currentPage variable?

  • I’d love to read this article, but this page is so damn slow. I cannot scroll without lagging. It’s annoying because I like this tutorial

    • Hi,
      Thanks for letting me know. Its been fixed now.
      Just clear your cache and reload the page. It should work fine.

      • It works now. Thanks for the hard work. I assume it’s because of the sidebar for sharing the article that caused this? I am still studying this code since I am creating a very similar app but with buy and sell app (like ebay).

        I write my own php code to get the database record. Can you suggest a way to write an sql code to get items since I write my sql with ‘LIMIT’ function. :/

        • Hey,
          It was indeed the side bar that was causing it. However I have no clue about PHP so I’m afraid I can’t help you there, sorry.

          • It’s fine. I have managed to fix this and it is now looking great especially with the error handling. 😀 Are you going to write about pull to refresh too?

          • Yeah, Pull to Refresh is in my todo list. Will be writing about it soon 🙂

          • Anyway, I kind of need help regarding the TOTAL_PAGE. If I increased it, it stops working altogether. Is there any other way to just keep loading without the total page?

          • Hey,
            There’s a slight change in the PaginationScrollListener. Please take a look at the updated file (link under source code section, end of post).

  • @suleiman to follow up with your previous FastAdapter blog post. The FastAdapter extensions also include some useful functions and helper classes for this. There is a full featured sample activity available: 😉

    But it is always great to show people how do these things with plain android 😉

    • Hi Mike,
      Thanks for the tip. Your library would always be my go to solution, had I remembered it when in need. However, like you said, sometimes plain android can get it done faster. Especially when people need time to familiarize with a new library 🙂