Reputation: 2280
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:
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
Upvotes: 8
Views: 5440
Reputation: 65
PagingDataAdapter has a flow attribute called loadStateFlow that contains state of the processed data inside.
You can try like this:
lifecycleScope.launchWhenCreated {
adapter.loadStateFlow.map { it.refresh }
.distinctUntilChanged()
.collect {
if (it is LoadState.NotLoading) {
// reset to position you wanted
}
}
}
LoadState.NotLoading is the specific state of loadStateFlow that corresponds to the state that processing data is finished.
Upvotes: 0
Reputation: 1605
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.
Upvotes: 3
Reputation: 3895
The method you're looking for is PagingSource.getRefreshKey()
. It's given the previous state, a PagingState
, which has the field PagingState.anchorPosition
, the last accessed index (including placeholders).
https://developer.android.com/topic/libraries/architecture/paging/v3-network-db#refresh-in-place
EDIT: I see now that you're using Room's implementation. There was actually a few bugs related to Remote REFRESH and its getRefreshKey implementation that should be resolved in the next release (alpha07). See https://issuetracker.google.com/issues/167260236
Upvotes: 1
Reputation: 417
Had the same issue. In my situation, I changed at PagingConfig enablePlaceholders to true and set initialLoadSize to be dividable to pageSize (for example, pageSize=10, initialLoadSize = 20).
Upvotes: 0