Restoring Scroll Position in Paging Library 3
Asked Answered
B

2

9

I am using Paging Library 3 with a RemoteMediator which includes loading data from the network and the local Room database. Every time I scroll to a certain position in the RecyclerView, navigate away to another Fragment, and then navigate back to the Fragment with the list, the scroll state is not preserved and the RecyclerView displays the list from the very first item instead of the position I was at before I navigated away.

I have tried using StateRestorationPolicy with no luck and can't seem to figure out a way to obtain the scroll position of the PagingDataAdapter and restore it to that same exact position when navigating back to the Fragment.

In my ViewModel, I have a Flow that collects data from the RemoteMediator:

val flow = Pager(config = PagingConfig(5), remoteMediator = remoteMediator) {
    dao?.getListAsPagingSource()!!
}.flow.cachedIn(viewModelScope)

and I am submitting that data to the adapter within my Fragment:

viewLifecycleOwner.lifecycleScope.launch {
    viewModel.flow.collectLatest { pagingData ->
        adapter?.submitData(pagingData)
    }
}

At the top of the Fragment, my adapter is listed as:

class MyFragment : Fragment() {

    ...

    private var adapter: FeedAdapter? = null

    ...

    override onViewCreated(...) {

        if (adapter == null) {
            adapter = FeedAdapter(...)
        }

        recyclerView.adapter = adapter

        viewLifecycleOwner.lifecycleScope.launch {
            viewModel.flow.collectLatest { pagingData ->
                adapter?.submitData(pagingData)
            }
        }
    }
}

How can we make sure that the adapter shows the list exactly where it was at before the user left the Fragment upon returning instead of starting the list over at the very first position?

Beatification answered 28/5, 2021 at 17:15 Comment(0)
R
9

Do this in your fragment's onViewCreated:

viewLifecycleOwner.lifecycleScope.launch {
    viewModel.flow.collect { pagingData ->                
        adapter.submitData(viewLifecycleOwner.lifecycle, pagingData)
    }
}
Reinold answered 10/6, 2021 at 18:11 Comment(2)
Thank you, this worked perfectly! Also a quick note: This will only work for immediate lifecycle owners so for direct Fragments and Activities only. If you try to use this within a child fragment that is living inside of another Fragment, then there will be some issues.Beatification
I have the same problem and this not works for me. Did you change anything in the PaginSource? Can you show it?Merta
H
1

After checking many solutions, this is the method that worked for me cachedIn()

fun getAllData() {
    viewModelScope.launch {
        _response.value = repository.getPagingData().cachedIn(viewModelScope)
    }
}
Housemother answered 6/11, 2022 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.