implement pagination with recyclerview poster

Easy Way To Implementing Pagination With Recyclerview

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

pagination with recyclerview sample

What is Recyclerview?

AndroidRecyclerViewis a more advanced, powerful, and flexible version of ListView. Android RecyclerView is similar to ListView except that it forces us to use RecyclerView.ViewHolder class to hold the elements that are not a compulsion in ListView.

As the name suggests, Android RecyclerView is used to reuse cells when scrolling up and down by recycling the items in the list. Another improvement in RecyclerView is that it allows us to set the LayoutManagers dynamically at runtime, unlike the ListView which was only available in a Vertical scrolling List. RecyclerView allows us to set the following types of Layouts at runtime.

LinearLayoutManager: it supports both vertical and horizontal lists.
StaggeredLayoutManager: it supports staggered lists.
GridLayoutManager: it supports displaying grids as seen in GalleryView earlier.

I have explained recyclerview in detail in the below link,

Recyclerview Android Example [Beginners]

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.

Now, do with the explanation.Let’s get started with the coding part of the pagination with recyclerview in android.

1. Setup dependency for the pagination with recyclerview

Add recyclerview, retrofit, and glide dependencies into the appbuild.gradlefile.

implementation 'com.android.support:recyclerview-v7:27.1.1'
    implementation 'com.android.support:cardview-v7:27.1.1'
    implementation 'com.squareup.retrofit2:retrofit:2.1.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
    implementation 'com.github.bumptech.glide:glide:4.7.1'

2. Prepare data for the recyclerview

In this example, I am using pagination withretrofit to load data from RESTAPI.

Retrofit android example kotlin[step by step]

Add Internet Permission to your Application inAndroidManifest.xml,

<uses-permission android:name=”android.permission.INTERNET”/>

Create the Retrofit instance

We need to create the Retrofit instance to send the network requests. we need to use the Retrofit Builder class and specify the base URL for the service.

public class ClientApi {

        private static Retrofit retrofit = null;

        public static Retrofit getClient() {
            if (retrofit == null) {
                retrofit = new Retrofit.Builder()
                        .addConverterFactory(GsonConverterFactory.create())
                        .baseUrl("https://velmm.com/apis/")
                        .build();
            }
            return retrofit;
        }

    }

Setting Up the Retrofit Interface

Retrofit provides the list of annotations for each HTTP method:

@GET,@POST,@PUT,@DELETE,@PATCH,or@HEAD.

The endpoints are defined inside of an interface using retrofit annotations to encode details about the parameters and request method. T return value is always a parameterizedCall<T>.

public interface MovieService {
        @GET("volley_array.json")
        Call<List<Movie>> getMovies();
    }

In my JSON response, I have a list of movies with names, and properties. So, My Model class will be like a Movie as class name and name, year, and director are properties.

public class Movie {

        @SerializedName("title")
        private String title;

        @SerializedName("image")
        private String imageUrl;

        public Movie(){}

        public Movie(String title, String imageUrl) {
            this.title = title;
            this.imageUrl = imageUrl;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getImageUrl() {
            return imageUrl;
        }

        public void setImageUrl(String imageUrl) {
            this.imageUrl = imageUrl;
        }
    }

3. Setup pagination with recyclerview

First, Add RecyclerView into activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clipToPadding="false"
            android:paddingBottom="24dp"/>

        <ProgressBar
            android:id="@+id/progressbar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"/>

    </FrameLayout>

Recyclerview Adapter for Pagination

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

class MovieViewHolder() — Recyclerview items

class LoadingViewHolder() — Footer ProgressBar used for Pagination

public class PaginationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

        private Context context;
        private List<Movie> movieList;
        private static final int LOADING = 0;
        private static final int ITEM = 1;
        private boolean isLoadingAdded = false;

        public PaginationAdapter(Context context) {
            this.context = context;
            movieList = new LinkedList<>();
        }

        public void setMovieList(List<Movie> movieList) {
            this.movieList = movieList;
        }

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            RecyclerView.ViewHolder viewHolder = null;
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());

            switch (viewType) {
                case ITEM:
                    View viewItem = inflater.inflate(R.layout.item_list, parent, false);
                    viewHolder = new MovieViewHolder(viewItem);
                    break;
                case LOADING:
                    View viewLoading = inflater.inflate(R.layout.item_progress, parent, false);
                    viewHolder = new LoadingViewHolder(viewLoading);
                    break;
            }
            return viewHolder;
        }

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

            Movie movie = movieList.get(position);
            switch (getItemViewType(position)) {
                case ITEM:
                    MovieViewHolder movieViewHolder = (MovieViewHolder) holder;
                    movieViewHolder.movieTitle.setText(movie.getTitle());
                    Glide.with(context).load(movie.getImageUrl()).apply(RequestOptions.centerCropTransform()).into(movieViewHolder.movieImage);
                    break;

                case LOADING:
                    LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
                    loadingViewHolder.progressBar.setVisibility(View.VISIBLE);
                    break;
            }
        }

        @Override
        public int getItemCount() {
            return movieList == null ? 0 : movieList.size();
        }

        @Override
        public int getItemViewType(int position) {
            return (position == movieList.size() - 1 && isLoadingAdded) ? LOADING : ITEM;
        }

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

        public void removeLoadingFooter() {
            isLoadingAdded = false;

            int position = movieList.size() - 1;
            Movie result = getItem(position);

            if (result != null) {
                movieList.remove(position);
                notifyItemRemoved(position);
            }
        }

        public void add(Movie movie) {
            movieList.add(movie);
            notifyItemInserted(movieList.size() - 1);
        }

        public void addAll(List<Movie> moveResults) {
            for (Movie result : moveResults) {
                add(result);
            }
        }

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

        public class MovieViewHolder extends RecyclerView.ViewHolder {

            private TextView movieTitle;
            private ImageView movieImage;

            public MovieViewHolder(View itemView) {
                super(itemView);
                movieTitle = (TextView) itemView.findViewById(R.id.movie_title);
                movieImage = (ImageView) itemView.findViewById(R.id.movie_poster);
            }
        }

        public class LoadingViewHolder extends RecyclerView.ViewHolder {

            private ProgressBar progressBar;

            public LoadingViewHolder(View itemView) {
                super(itemView);
                progressBar = (ProgressBar) itemView.findViewById(R.id.loadmore_progress);

            }
        }

    }

In this post, I am using Glide to load data from the URL.

Glide Library – Image Loading Library For Android

To enable Pagination, we must detect the user reaching the end of the RecyclerView items. For that,PaginationScrollListener extends the RecyclerView.OnScrollListener and override theonScrolled()method.

public abstract class PaginationScrollListener extends RecyclerView.OnScrollListener {

        private LinearLayoutManager layoutManager;

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

        @Override
        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) {
                    loadMoreItems();
                }
            }
        }

        protected abstract void loadMoreItems();

        public abstract boolean isLastPage();

        public abstract boolean isLoading();

    }

Finally, Attach pagination with recyclerview to load more items when scrolling.

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
            paginationAdapter = new PaginationAdapter(this);
            recyclerView.setLayoutManager(linearLayoutManager);
            recyclerView.setAdapter(paginationAdapter);

            recyclerView.addOnScrollListener(new PaginationScrollListener(linearLayoutManager) {
                @Override
                protected void loadMoreItems() {
                    isLoading = true;
                    currentPage += 1;
                    loadNextPage();
                }

                @Override
                public boolean isLastPage() {
                    return isLastPage;
                }

                @Override
                public boolean isLoading() {
                    return isLoading;
                }
            });

            loadFirstPage();
        }

        private void loadNextPage() {

            movieService.getMovies().enqueue(new Callback<List<Movie>>() {
                @Override
                public void onResponse(Call<List<Movie>> call, Response<List<Movie>> response) {
                    paginationAdapter.removeLoadingFooter();
                    isLoading = false;

                    List<Movie> results = response.body();
                    paginationAdapter.addAll(results);

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

                @Override
                public void onFailure(Call<List<Movie>> call, Throwable t) {
                    t.printStackTrace();
                }
            });
        }

        private void loadFirstPage() {

            movieService.getMovies().enqueue(new Callback<List<Movie>>() {
                @Override
                public void onResponse(Call<List<Movie>> call, Response<List<Movie>> response) {
                    List<Movie> results = response.body();
                    progressBar.setVisibility(View.GONE);
                    paginationAdapter.addAll(results);

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

                @Override
                public void onFailure(Call<List<Movie>> call, Throwable t) {

                }

            });
        }

Now, we have implemented the recyclerview with pagination.

You can download the source code for this example on GitHub.

Conclusion

Thanks for reading. Please try this example yourself and let me know your feedback in the comments.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *


Latest Posts