android / codelab-android-paging

Jetpack Paging codelab
Apache License 2.0
494 stars 263 forks source link

step 9 scroll not sync with diff util #149

Closed P1NG2WIN closed 3 years ago

P1NG2WIN commented 3 years ago

faced this problem https://stackoverflow.com/questions/65882817/paging-3-how-to-scroll-to-top-of-recyclerview-after-pagingdataadapter-has-fini?noredirect=1#comment116810306_65882817

johnjake commented 3 years ago

@P1NG2WIN, We call refresh because of the following we modify the existing value, remove or add new value. This will also requires to update your DBTable and RemoteKeys Table and you need to add a logic on LoadType.REFRESH and since you need to update both tables, your DBTable and RemoteKeys Table, you need also to determined what type of modification, ADD, DELETE or UPDATE then update your list, thats why its much easier to clear or remove all values in the tables then insert the modified list than keeping or updating the old values.

jonathansds commented 3 years ago

Do we have any update on this? I am facing the same problem and in my case, deleting all entities from database inside mediator just to trigger PagingSource.invalidate is not an option as it will trigger cascade deletion on children entities and parallel calls will run into SQL ForeignKey violations...

jonathansds commented 3 years ago

I was able to achieve this using:

adapter.loadStateFlow
        .distinctUntilChanged { old, new ->
                old.mediator?.prepend?.endOfPaginationReached.isTrue() ==
                new.mediator?.prepend?.endOfPaginationReached.isTrue() }
        .filter { it.refresh is LoadState.NotLoading }
        .collect {
                mBinding.fragmentList.postDelayed({ mBinding.fragmentList.scrollToPosition(0)}, 300)
        }

Which is based on the solution proposed here. Even though it works fine, it prevents the StateRestorationPolicy.PREVENT_WHEN_EMPTY to work resulting on list being scrolled to top when phone screen rotates or any other configuration change.

tunjid commented 3 years ago

@P1NG2WIN @jonathansds have you pulled the latest version of the code lab? It was updated recently. The scroll to top is only called after the submit data has finished suspending now.

jonathansds commented 3 years ago

@P1NG2WIN @jonathansds have you pulled the latest version of the code lab? It was updated recently. The scroll to top is only called after the submit data has finished suspending now.

I am using version 3.0.1 which is the one showing on https://developer.android.com/topic/libraries/architecture/paging/v3-overview. Is there a more recent one?

jonathansds commented 3 years ago

@P1NG2WIN @tunjid I can confirm we don't need the postDelayed to scroll to top using version 3.1.0-alpha03 released on 21/07/2021. Also, I managed to make further filter the loadStateFlow collection so it doesn't prevent StateRestorationPolicy.PREVENT_WHEN_EMPTY to work. My solution is:

By the time I am writing this, the latest version of Paging3 is 3.1.0-alpha03 so import:

androidx.paging:paging-runtime-ktx:3.1.0-alpha03

Then set the restoration policy of your adapter as following:

adapter.stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY

If you have compilation error for the above mentioned change, make sure you are using at least version 1.2.0-alpha02 of RecyclerView. Any version above that is also good:

androidx.recyclerview:recyclerview:1.2.0-alpha02

Then use the filtered loadStateFlow to scroll the list to top only when you refresh the page and items are prepended in the list:

viewLifecycleOwner.lifecycleScope.launch {
            challengesAdapter.loadStateFlow
                .distinctUntilChanged { old, new ->
                    old.mediator?.prepend?.endOfPaginationReached.isTrue() ==
                            new.mediator?.prepend?.endOfPaginationReached.isTrue() }
                .filter { it.refresh is LoadState.NotLoading && it.prepend.endOfPaginationReached && !it.append.endOfPaginationReached}
                .collect {
                    mBinding.fragmentChallengesByLocationList.scrollToPosition(0)
                }
        }
tunjid commented 3 years ago

Oh I meant the latest version of the code lab as the original issue referenced the code lab. I'm glad you were able to resolve your issue, I'll close this now.

d9j commented 2 years ago

the issue is closed but still unclear how to resolve this problem. here offered some hacks https://www.reddit.com/r/androiddev/comments/lb7ys6/scrolling_up_after_refresh_with_pagingdataadapter/glvoti6/ In the end i realize that google often provides some over engineered crap which often difficult to figure out how to resolve the issue because of all that complexity it offers