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.
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.gradle
file.
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.
Leave a Reply