Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restore recyclerview scroll position when using PagingDataAdapter?

I have an App that fetches a list of 158 Items from an API, stores it in Room, and displays it to the user. RoomDB is the source of truth.

This is the code on my ViewModel that gets the result from the database:

private val pagingConfig =
    PagingConfig(pageSize = 20, enablePlaceholders = false, maxSize = 300)

fun getList(filters: Filters): Flow<PagingData<Character>> {
    return Pager(pagingConfig) {
        repository.getCharacters(filters)
    }.flow.map {
        it.asDomainModel()
    }
}

This is the code on my fragment that populates the adapter:

private fun fetchData(filters: Filters) {
    lifecycleScope.launch {
        charactersViewModel.getList(filters).collectLatest { pagedList ->
            characterAdapter.submitData(pagedList)
        }
    }
}

Current behaviour:

  • When a configuration change occurs after my 60th Item, the scroll position is lost, I've found out that increasing the pageSize on my pagingConfig from 20 to 55, it fixes this issue.

What I have already tried:

Since I'm fetching the data asynchronously I've tried using this piece of code from this article to prevent loading the data when adapter is empty. but it didn't work

characterAdapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY

What I expect to achieve:

Be able to scroll to the bottom of the list and do configuration changes without loosing the scroll position "without having the need to increase my pageSize as the list gets bigger"

https://github.com/doilio/DC-Characters

like image 337
Doilio Matsinhe Avatar asked Oct 27 '22 19:10

Doilio Matsinhe


1 Answers

Don't return a new instance of Flow<PagingData> evertime from your getList method.

Do something like this:

class YourViewModel: ViewModel() {
   private mPagingData = Flow<PagingData<Character>>? = null;

   fun getList(filters: Filters): Flow<PagingData<Character>> {
      if(mPagingData != null) return mPagingData; //This is important
      else
         mPagingData = Pager(pagingConfig) {
              repository.getCharacters(filters)
         }.flow.map {
              it.asDomainModel()
         }
      return mPagingData;
   }
}

Apart from this, make sure you initialize your adapter in onCreate of your fragment.

like image 50
artenson.art98 Avatar answered Nov 15 '22 06:11

artenson.art98