DEV Community

Cover image for RecyclerView pagination scroll listener in Android
Mohit Rajput
Mohit Rajput

Posted on

RecyclerView pagination scroll listener in Android

What is pagination

Loading a list of items in batches instead of loading all items in a single go is called pagination. When you open the Gmail web app, you see 50 emails by default in a single page. To see the 51st mail, you have to click on next page button.

Why pagination

Consider in your Gmail account, there are about one thousand plus emails. Loading all a thousand emails at once will have the following drawbacks:

  • Database read operation will be very costly. So you will get a list with a great amount of latency.
  • After fetching the list, rendering a large number of items in a single go can slow down GUI.

Ways to use pagination

In Android, there are two ways to implement pagination:

  1. Using jetpack's paging library. You can see the detailed implementation of the paging library using MVVM in my other blog Paging with MVVM and coroutines.
  2. Using our own implementation of RecyclerView scroll listener.

Simple scroll listener

This article focuses on our own implementation. There are many ways to implement logic inside the scroll listener of RecyclerView. I have created a generic implementation of scroll listener which you can simply copy-paste into your code:


/**
 * Created by Mohit Rajput on 20/03/22.
 * Used for the load more functionality.
 */
abstract class PaginationScrollListener(private val layoutManager: LinearLayoutManager) :
    RecyclerView.OnScrollListener() {

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)
        val visibleItemCount: Int = layoutManager.childCount
        val totalItemCount: Int = layoutManager.itemCount
        val firstVisibleItemPosition: Int = layoutManager.findFirstVisibleItemPosition()
        if (!isLoading() && !isLastPage()) {
            if (visibleItemCount + firstVisibleItemPosition >= totalItemCount
                && firstVisibleItemPosition >= 0
            ) {
                loadMoreItems()
            }
        }
    }

    protected abstract fun loadMoreItems()
    abstract fun isLastPage(): Boolean
    abstract fun isLoading(): Boolean
}
Enter fullscreen mode Exit fullscreen mode

Here is an example usage of this scroll listener:


private var isLoadingEmails = false
private val viewModel by viewModels<EmailsViewModel>()

private fun addScrollListener() {
        recyclerView.addOnScrollListener(object :
            PaginationScrollListener(recyclerView.layoutManager as LinearLayoutManager) {
            override fun loadMoreItems() {
                viewModel.fetchEmails()
            }

            override fun isLastPage() = viewModel.isAllEmailLoaded

            override fun isLoading() = isLoadingEmails
        })
    }
Enter fullscreen mode Exit fullscreen mode

Explanation

  • When you start loading the list, set isLoadingEmails value to true. Once loaded, set it to false. This can be managed by view state triggered through live data or state flow.
  • viewModel.isAllEmailLoaded value depends on API call implementation. If your API provides the total count of list items, you can simply implement it as isAllEmailLoaded = currentList.size == totalListItems.
  • This implementation is for LinearLayoutManager only. I will provide an efficient code for GridLayoutManager soon.

Conclusion

Load more or pagination is a widespread concept that almost every app uses. We write the code of the scroll listener again and again. So I created a small generic class that structures the load more so that it can be reused easily. If loading is in progress, it will not make a loading call simultaneously. 
Thanks for the reading. 😊😊😊

Top comments (1)

Collapse
 
arthacker8209 profile image
Deepak Kumawat

Very Informative.. Going to use in every application.