Android Pagination: Error Handling

Endless or Infinite scrolling is called pagination. You do this in Android using RecyclerView. However there are few critical error scenarios to handle.

This is the third post in a series of Android Pagination articles.

In the previous, Android Pagination: Using APIs with Retrofit and Gson article, we fetched real API data in Pagination. We used for our data source. Additionally Retrofit was used for networking, Glide for image loading and Gson for JSON parsing.

However, when networking is involved, one simply cannot ignore the various errors that occur. A good app intelligently handles all errors. This article aimed towards that.

Pagination Series Overview

  1. Android Pagination 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)

Unlike one-off API calls, which involves one request to display data on-screen, Pagination is different.

Those who’ve followed my Pagination post series, know the first page call happens separately. This means, error handling for page 1 will be different than that for page 2 and beyond.

Pagination involves 2 crucial error handling scenarios. Let’s deal with both.

Pagination Error Handling for Page 1

For pagination, page 1 is our one-off API call.

Now if the API call fails here, the screen will be empty with nothing to display. So unless you have cached data as backup, you have nothing to show.

One-off loading content

So what can we do? Use the entire screen to tell people what went wrong.

Ideally, stick to a crisp one or two liner about the error. Nothing too technical. Also, don’t forget to include a ‘Call-to-Action’ (CTA) button.

Mostly, the CTA would and should be a retry button.

Here’s how I’ve modified my existing screen to accommodate an error layout:

activity_main.xml layout skeleton

    < />
    <include layout="@layout/error_layout"/>




        <!--Displays a generic error message-->

  <!--Displays a reason for the error—>
            tools:text="The server took too long to respond."/>

        <!—CTA— prompting user to retry failed request>


One-off API call error layout

Use humor to reduce the  seriousness of error

While this is the bare minimum, use the available screen estate effectively. Use this opportunity to display an image associated with the error. Even better if you can use a short GIF to go with it.

Some examples from

Google Playbook – Error Animation by Ben Breckler


Error Screen by Amit Nanda

Remember, adding a bit of humor goes a long way. But this may offend a few, so use it sparingly.

Handling Failure

Once the call fails, we must do three things:

  1. Hide the ProgressBar (loading indicator)
  2. Display error layout
  3. Show the appropriate error message

We can handle all of this by writing a convenient method showErrorView(Throwable t) called in onFailure() of our API call.

callTopRatedMoviesApi().enqueue(new Callback<TopRatedMovies>() {
           public void onResponse(Call<TopRatedMovies> call, Response<TopRatedMovies> response) {
               // TODO: handle data

           public void onFailure(Call<TopRatedMovies> call, Throwable t) {

 private void showErrorView(Throwable throwable) {
       if (errorLayout.getVisibility() == View.GONE) {

           // display appropriate error message
           // Handling 3 generic fail cases.
           if (!isNetworkConnected()) {
           } else {
               if (throwable instanceof TimeoutException) {
               } else {

showErrorView() takes a Throwable parameter, that can be used to know what the error is.

Don’t forget to hide the error view! A good place to do this is BEFORE executing your API call.

Notice our error layout has a retry button. This is our CTA which effectively allows to retry the failed request. So hopefully our screen will have something to show now.

Next, let’s add a click listener.

 btnRetry.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view { 

The button allows users to retry the first request, if it failed.

Let’s run through a quick recap of what we just did. We:

  1. modified our activity_main.xml layout to include an error view
  2. displayed error view whenever the one-off API call failed
  3. used onFailure() to display appropriate error message
  4. allowed users to retry request after failure, via a CTA (Retry Button)

Pagination Error Handling for Page 2 and above

As mentioned earlier, errors for page 2 and above will be handled differently. Initially, when expecting a page to load, a ProgressBar (loading indicator) is display at the footer.

If the API successfully returns a response, then we remove our ProgressBar and append the new data. However, for some reason if that fails, we need to handle it.

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!

Similar to page 1, we need to do two things:

  1. Hide the footer ProgressBar and show an error (in the footer) instead
  2. Tell the user what went wrong
  3. Allow them to retry

While the steps to perform remain the same, the key difference lies in executing this and displaying it to the user.

Open item_progress.xml. We need to add an error layout to this.




            android:src="@drawable/ic_refresh_black_24dp" />


                tools:text="What went wrong"/>



(Footer) Progress layout with retry UI

Notice that our design now does two things. It:

  1. allows a user to retry
  2. tells them what went wrong

Listening to Retry button clicks

Go to Let’s add the click action for the retry button.

protected class LoadingVH extends RecyclerView.ViewHolder implements View.OnClickListener {
     private ProgressBar mProgressBar;
     private ImageButton mRetryBtn;
     private TextView mErrorTxt;
     private LinearLayout mErrorLayout;

     public LoadingVH(View itemView) {

         mErrorTxt = (TextView) itemView.findViewById(;
         mErrorLayout = (LinearLayout) itemView.findViewById(;


     public void onClick(View view) {
         switch (view.getId()) {
                 showRetry(false, null);

Notice that mCallback.retryPageLoad() is a listener which MainActivity will implement.

public interface PaginationAdapterCallback {
    void retryPageLoad();

Head back to and implement PaginationAdapterCallback interface. Then, go to the loadNextPage() method and make the following changes:

private void loadNextPage() {
       Log.d(TAG, "loadNextPage: " + currentPage);

       callTopRatedMoviesApi().enqueue(new Callback<TopRatedMovies>() {
           public void onResponse(Call<TopRatedMovies> call, Response<TopRatedMovies> response) {
               isLoading = false;

           public void onFailure(Call<TopRatedMovies> call, Throwable t) {
   adapter.showRetry(true, fetchErrorMessage(t));

Add the showRetry() method in

public void showRetry(boolean show, @Nullable String errorMsg) {
      retryPageLoad = show;
      notifyItemChanged(movieResults.size() - 1);

      if (errorMsg != null) 
    	this.errorMsg = errorMsg;

adapter.showRetry() is responsibly for changing the footer ProgressBar into a retry button. It additionally displays an error message saying what went wrong.


Displaying an error message matters

Typically, apps tend to show a retry button on failure. They miss out on telling us what exactly went wrong. The reason for failure could be anything. Does the user have a network issue? Or did the server fail to respond?

Most importantly, the error message tells us on whose side the issue is.

Here is how Instagram and DailyHunt (NewsHunt) handle pagination errors:

Pagination error handling in Instagram

DailyHunt pagination error handling

Take a good look at both these examples. Which one do you think did a better job of telling you what went wrong? That’s right, Dailyhunt. The app clearly tells us what the issue is. Also, it tells us what to do, to rectify it. Finally, the error footer is clickable, allowing us to retry that failed request.

While Instagram certainly does have a clean design, simply showing a retry option doesn’t really tell us the problem.

Finally, with everything done, let’s go ahead and run our app.

Final Results

We’ve now successfully handled both use cases. Page 1 is a separate call compared to the rest of the pages.

When page 1 fails, we don’t have any content to show the user. This leaves the entire screen blank. We handled this by smartly using the available screen estate. An appropriate error message was displayed. Additionally, we allowed users to retry the failed request.

We then followed a similar approach to handle page 2 and beyond. In addition to display a retry button in the footer, we displayed the reason for failure as well. Finally, we inferred from 2 famous apps about how they handled a similar scenario.


View Project on GitHub


Some key takeaways:

  • Pagination primarily has 2 error cases to be handled
  • Errors can be unavoidable, but we can take steps to handle them
  • Tell users what exactly went wrong, but don’t get too technical
  • Be forgiving with errors (consider using humor) and allow users to retry requests

Hope this post helped make your paginated apps error-prepared. As always, I’d like to hear what you think. Tell me if I covered all use cases. Did I miss out anything? Drop ’em in the comments below.

I’m happy you took the time to read this. All I need for you is to help me spread the word!

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...

  • I really love your tutorials. I am learning a lot.:3

  • Ilya

    Thanks for tutorial, it`s really cool !
    But I have a null pointer exception with your code. Can you help me& Thanks in advance.

    E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.lukienko.movieapp, PID: 25633
    java.lang.NullPointerException: Attempt to invoke virtual method ‘java.util.List com.lukienko.movieapp.models.TopRatedMovies.getResults()’ on a null object reference
    at com.lukienko.movieapp.MainActivity.fetchResults(
    at com.lukienko.movieapp.MainActivity.access$700(
    at com.lukienko.movieapp.MainActivity$3.onResponse(
    at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$
    at android.os.Handler.handleCallback(
    at android.os.Handler.dispatchMessage(
    at android.os.Looper.loop(
    at java.lang.reflect.Method.invoke(Native Method)

    • Hi,

      This error is most likely because of an issue with the API call’s response. Are you getting a response from the API?

  • Andy Smith

    Thanks for this awesome toturials. Please post Github code for this tuttorial

    • Hi Andy,

      You’re welcome. Post is now updated with GitHub link (see end of post). Sorry about that!

      • Andy Smith

        Thanks so much!