DEV Community

Ajinkya Patil
Ajinkya Patil

Posted on • Updated on

RecyclerView Pagination in MVVM(Model-View-ViewModel) architecture using Scroll Listener

Why Pagination

While using social media apps, we scroll until all posts from our social network are seen. Consider there are hundreds plus posts in your social media app. Requesting all data at once will have the following drawbacks:

  • List loading time will be high.
  • Rendering all data on UI at once will cause a longer wait time for the user.

What is Pagination

Requesting data in bits instead of requesting all at once is called Pagination. When you open the Instagram app and scroll, it will show a list of posts. After some posts, an indicator will be shown at the bottom and it will request new posts.

Implementation

There are 2 ways to implement Pagination in Android:

  • Using RecyclerView Scroll Listener
  • Using Jetpack’s Paging library. To implement using the Paging library, follow the below link:

https://developer.android.com/topic/libraries/architecture/paging/v3-overview?source=post_page-----19be70c31a30--------------------------------

Implementation using Scroll Listener

In your Activity/Fragment, add scroll listener as follows:

linearLayoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
binding.rvListPurchaseOrderLines.layoutManager = linearLayoutManager
binding.rvListPurchaseOrderLines.adapter = adapter
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)
        val visibleItemCount = linearLayoutManager.childCount
        val totalItemCount = linearLayoutManager.itemCount
        val firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition()

        if (!viewModel.isLoading.value!! && 
            (visibleItemCount + firstVisibleItemPosition) >= totalItemCount && 
            firstVisibleItemPosition >= 0) {
            viewModel.fetchNextPage()
        }
    }
})
Enter fullscreen mode Exit fullscreen mode

In View Model, request next page data as follows:

class MyFeedsViewModel(private val repository: MyFeedsRepository) : ViewModel() {
    val feedsDataList: LiveData<List<MyFeedsData>> = MutableLiveData()
    val isLoading: LiveData<Boolean> = MutableLiveData()

    private var currentPage = 1

    fun fetchNextPage() {
        viewModelScope.launch {
            isLoading.postValue(true)
            val newData = repository.fetchData(page = currentPage)
            val currentData = feedsDataList.value ?: emptyList()
            (feedsDataList as MutableLiveData).postValue(currentData + newData)
            isLoading.postValue(false)
            currentPage++
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In Repository, fetch data from DB, network, etc as follows:

class MyFeedsRepository {
    suspend fun fetchData(page: Int): List<MyFeedsData> {
    // You can fetch data from network, DB, etc.
       return database.feedsListDAO().getFeedsList()
   }
}
Enter fullscreen mode Exit fullscreen mode

In Fragment/Activity, observe live data as follows:

viewModel.feedsDataList.observe(this, Observer { dataList ->
    adapter.submitList(dataList)
})

viewModel.isLoading.observe(this, Observer { isLoading ->
    if(isLoading) {
        progressBar.visibility = View.VISIBLE
    } else {
        progressBar.visibility = View.GONE
    }
})
Enter fullscreen mode Exit fullscreen mode

That’s it! With this setup, your RecyclerView will fetch new pages of data as the user scrolls. Adjust the specifics of the data fetching and update logic according to your needs. Thanks for reading.

Top comments (0)