Android Pagination: Using APIs with Retrofit and Gson

Let’s look at Android Pagination with RecyclerView, using real data from an API. This will give us a better understanding of Pagination. First, we’ll look at what API to use. Next we will setup a networking library (Retrofit) that will help us perform these API calls.

This is the second post in a series of Android Pagination articles. In the previous, Android Pagination Tutorial: Getting Started article, we learnt about Pagination and implemented its logic. We created dummy content to populate our RecyclerView.Adapter.

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)

In this post, we will look at fetching data from an API, as a real-time scenario. This will give us a better understanding of Android Pagination. First, we’ll look at what API to use. Next we will setup a networking library (Retrofit) that will help us perform these API calls.

For a real-world scenario, we’ll need real content from an API. For that, let’s go with A popular, user maintained database for movies and TV shows.

The Movie DB API

We need an API key, before we can start using their APIs. So go ahead and sign up.

Next, login in and go to your account. Generate an API key from there. Be advised, there’s a fairly long form you need to fill. The API is free, so the least we can do is fill a form. So do swift of that, and get your key.
After that, either go through their documentation for an in-depth usage. Otherwise for the scope of this tutorial, we’ll simply make a request to find ‘top rated movies’. You could use a URL of your own choice, or follow along with me.

API Call for Top Rated Movies

Here’s the shortest URL we need:

Just remember to replace YOUR_API_KEY with your actual API key!

JSON Response for Top Rated Movies

  "page": 1,
  "results": [
      "poster_path": "\/9O7gLzmreU0nGkIB6K3BsJbzvNv.jpg",
      "adult": false,
      "overview": "Framed in the 1940s for the double murder of his wife and her lover, upstanding banker...",
      "release_date": "1994-09-10",
      "genre_ids": [
      "id": 278,
      "original_title": "The Shawshank Redemption",
      "original_language": "en",
      "title": "The Shawshank Redemption",
      "backdrop_path": "\/xBKGJQsAIeweesB79KC89FpBrVr.jpg",
      "popularity": 8.522754,
      "vote_count": 5493,
      "video": false,
      "vote_average": 8.34
  … // Other result (movie) objects
  "total_results": 4341,
  "total_pages": 218

Notice the page attribute in the response. It starts from 1. We also get a nice response that tells us the total_pages is 218. That means we can Pagination 218 times in total, with about 20 content per page! However, we don’t need that much, so for this tutorial, let’s stick to 5 pages in total?

I recommend using Postman when dealing with APIs. It gives you a clear idea on how to construct proper API requests. Also, the formatted JSON response is handy too.

Before we begin, we’ll need to decide upon a networking library (and image loading library too, if you wish). Dealing with text and media in APIs is pretty common, so I’ll assume we need both. These libraries will do most of the heavy-lifting, allowing us to focus on the app itself.

Tech Stack:

  1. Gson – library to convert Java Objects into their JSON representation and back
  2. Retrofit – HTTP client for Android
  3. Glide – image loading and caching library for Android; handy for smooth scrolling

You might be familiar with Retrofit and Gson. They’re a powerful combination, often preferred when dealing with APIs. The Codepath guides is a perfect place to start for the uninitiated:

However, not to worry if you’re unfamiliar with them. I’ll be going over the basics. Just enough to get your app working!

Getting Started

Start by adding Gson, Retrofit and Glide to your app/build.gradle.

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.github.bumptech.glide:glide:3.7.0'

Additionally, we need a Gson converter for Retrofit. It allows serialising JSON responses to model classes using Gson, automagically! This allows us to work with data, via models. So, no more manual JSON parsing!

Don’t forget to add the internet permission in AndroidManifest.xml!

<uses-permission android:name="android.permission.INTERNET"/>
This is not a tutorial about using Retrofit. However I will go through the bare minimum that’s required to setup Retrofit and use it.

Preparing Model Classes with Gson

We need to create model classes that mirror our API response. While you can take your time to manually create this, I want to automate it. We already know how our API response looks like. So let’s auto-generate our model classes and save ourselves time.

Head over to and paste your API response. Set the parameters on the right as follows:

  1. Set the (project) package name and parent model class name (ideally should be the name of the API call, i.e. TopRatedMovies)
  2. Set Source Type as JSON
  3. Set Annotation Style as GSON

Finally, hit Zip to generate the class files and download them. Or , you can get the files directly from me. 🙂

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!

Let’s take a quick breather here. Did you just see what we did? We auto-generated all the model classes we need to handle a particular API response. Just how amazing is that!?

Either way, you’ll end up with two model classes. Parent model TopRatedMovies, and the other model is automatically named Result. Notice how each model’s property is annotated to its JSON response attribute. Gson uses these annotations to map the JSON values to its respective model properties.

With this done, we can proceed to setting up Retrofit.

Modifying PaginationAdapter

Compare the API response with our model classes. Each movie object in the array is, and the entire response is

Also, consecutive page requests indicate multiple TopRatedMovies model. This implies that our RecyclerView.Adapter must use List<TopRatedMovies>. So go ahead and modify PaginationAdapter to use the same.

Updated PaginationAdapter can be found here.

Delete the model class as its no longer needed.

Configuring Retrofit

Create a class This will be responsible for configuring Retrofit client. Next, create an interface called MovieService. We will define all our API calls here. Retrofit uses Annotations to define API calls.

Open We’ll now configure the Retrofit client.

public class MovieApi {
    private static Retrofit retrofit = null;

    public static Retrofit getClient(Context context) {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
        return retrofit;
Remember that the base URL must always end with a forward trailing slash.

Now, head over to We will define our top rated movies API call here.

// Declare all your API calls here
public interface MovieService {

    Call<TopRatedMovies> getTopRatedMovies(
            @Query("api_key") String apiKey,
            @Query("language") String language,
            @Query("page") int pageIndex

 Making API Calls with Retrofit

Go to MainActivity. If you remember from Part 1 of the Android Pagination tutorial, there is a method called loadFirstPage(). We were loading dummy data here at first. Scrap those lines off. Now we’re going to perform the API request here. We’ll start by requesting for the very first page, i.e. page 1.

protected void onCreate(Bundle savedInstanceState) {
   //init service and load data
   MovieService movieService = MovieApi.getClient().create(MovieService.class);	//1
 * Performs a Retrofit call to the top rated movies API.
private Call<TopRatedMovies> callTopRatedMoviesApi() {	//2
    return movieService.getTopRatedMovies(
 * Extracts List<Result> from response
private List<Result> fetchResults(Response<TopRatedMovies> response) {	//3
    TopRatedMovies topRatedMovies = response.body();
    return topRatedMovies.getResults();
private void loadFirstPage() {
    callTopRatedMoviesApi().enqueue(new Callback<TopRatedMovies>() {	//4
        public void onResponse(Call<TopRatedMovies> call, Response<TopRatedMovies> response) {
            List<Result> results = fetchResults(response);	//5

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

        public void onFailure(Call<TopRatedMovies> call, Throwable t) {
            // handle error
private void loadNextPage() {
    callTopRatedMoviesApi().enqueue(new Callback<TopRatedMovies>() {	//6
        public void onResponse(Call<TopRatedMovies> call, Response<TopRatedMovies> response) {
            isLoading = false;

            List<Result> results = fetchResults(response);

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

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

Here are crucial snippets of an updated Let’s go over what each of the commented steps mean.

  1. Start by initialising MovieService object with a Retrofit instance. Look at getClient() method in, you’ll notice that it builds a configured Retrofit instance.
  2. callTopRatedMoviesApi() returns the Retrofit API call since we’ll be reusing the same. The method parameters passed here are query parameters for the API’s URL.
  3. Another helper method that extracts the list of results (movies) from the API response.
  4. Attach an API callback using enqueue() to handle the response.
  5. Notice how the callback returns Response<TopRatedMovies> and not a generic JSON String. This is the magic of Gson. It serialised the entire response into TopRatedMovies. However, what we actually need is a list of movies give by List<Results> from TopRatedMovies class.
  6. We use the same API call for loading the next page too. mCurrentPage is incremented by PaginationScrollListener, so the API loads the indicated page number

If you noticed back in the API response, Pagination starts from page 1. There is no index zero. Hence change PAGE_START = 1. Additionally, the response includes other useful information such as up to how many pages we can paginate.

Updating PaginationAdapter to display API data

Now, we have a working API call with a response, so head over to PaginationAdapter. First, we start by updating our helper methods. If you can recall, we had defined the following methods in Part 1:

void add(Result r)
void addAll(List<Result> moveResults)
void remove(Result r) 
void clear()
boolean isEmpty()
void addLoadingFooter()
void removeLoadingFooter()
Result getItem(int position)
We don’t use the Movie model class anymore. Instead our ‘Movie’ object is now replaced by So update your methods accordingly!

Next, our list of data will now become a List<Result> object. So change that in your adapter as well, if you haven’t.

With that done, the last step is to update onBindViewHolder() with our new data.

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        Result result = movieResults.get(position); // Movie

        switch (getItemViewType(position)) {
            case ITEM:
                final MovieVH movieVH = (MovieVH) holder;


                        result.getReleaseDate().substring(0, 4)  // we want the year alone
                                + " | "
                                + result.getOriginalLanguage().toUpperCase()


                 // Using Glide to handle image loading.
                        .load(BASE_URL_IMG + result.getPosterPath())
                        .listener(new RequestListener<String, GlideDrawable>() {
                            public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                                // handle failure
                                return false;

                            public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                                // image ready, hide progress now
                                return false;   // return false if you want Glide to handle everything else.
                        .diskCacheStrategy(DiskCacheStrategy.ALL)   // cache both original & resized image


            case LOADING:
//                Do nothing

Don’t forget to update your ViewHolder item layout accordingly. For example, here’s how I’ve modified mine to display the new data. However I’m sure you can come up with something better!

Adapter item layout


Now that we’ve done everything needed, go ahead and run your app. Here’s how the output should look like:



You might noice duplicated contents at the end and beginning of consecutive pages.  Eg: The movie ‘Empire Strikes Back’, might appear twice. This occurs twice in the paginated response and is no cause for alarm.

Project Available on GitHub

View Source CodeView Commit 'Pagination: Handling API Content with Retrofit and Gson'

In this post, we were able to take Pagination and apply it to a real-world example using an API. We used Retrofit to handle our networking, Gson to maintain our model classes and auto-parse JSON results. We also used Glide to make image handling a breeze. Next, we updated our existing code to reflect the new API.

However with network and API calls in play, we cannot ignore the scenario of an API call failing. Nor can we ignore when our mobile data or Wi-Fi stops working. Error handling becomes imperative in such cases.

In the next post, I’ll show you how to deal with such cases. Part 3 of the post coming soon. To know when its available, subscribe to the newsletter below!

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

Enjoyed this article? Please spread the word.

Subscribe to Newsletter
Be the first to get latest updates and exclusive content
straight to your email inbox.
Chill, I hate spam too. You can unsubscribe anytime.

Top Recommended Books by StackOverflow Users


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

You may also like...

Enjoyed this article? Please spread the word.

Subscribe to Newsletter
Be the first to get latest updates and exclusive content
straight to your email inbox.
Chill, I hate spam too. You can unsubscribe anytime.

Gradle setup, ProGuard rules, Material Design palette, metrics and much more

FREE Material Design Starter Project

For more details, click on the below link.
Download FREE
Material Design Template Project for Android Studio
Develop faster with an all-in-one, customizable Material Design App
Don't miss this App Template!