RecyclerView Pagination in MVVM(Model-View-ViewModel) architecture using Scroll Listener
Tags: android, kotlin, mvvm
Published: 2023-10-24 07:01:51

**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--------------------------------](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()
        }
    }
})
```

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++
        }
    }
}
```

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()
   }
}
```

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
    }
})
```
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.