2

There is a situation where I have to scroll the recyclerview to last position. The problem starts where I am using Paging 3. I don't know what is the proper way to do it every time I submit data to adapter. by the way I have to say that I do not submit data once, but for example every time user submits a new comment to backend I have to get the new list from server and submit it.
This is what I tried. that's how I observe data:

private fun observeComments() {
        exploreViewModel.commentsLiveData.observe(viewLifecycleOwner) { comments ->
            commentsAdapter.submitData(viewLifecycleOwner.lifecycle, comments)
        }
    }

And this is how I tried to scroll the recyclreview to last item:

commentsAdapter.addLoadStateListener { loadStates ->
            if(loadStates.refresh.endOfPaginationReached){
                if(commentsAdapter.itemCount>1)
                    binding.rvComments.smoothScrollToPosition(commentsAdapter.itemCount-1)
            }
        }

I also set app:stackFromEnd="true" to recyclerview but this is not useful. whenever I submit a new comment and get the list, recyclerview scrolls to the middle, I thinks it scrolls to the first pages end. but I want it to be scrolled to the end of the list.
Any help or suggestion would be appreciated.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Reza
  • 845
  • 13
  • 18

1 Answers1

0

You can implement PagingSource.getRefreshKey() to control the key passed to .load() after invalidation and set initialKey in Pager() to control the key passed to initial call of .load().

Since your list is paginated, scrolling to the end doesn't work because you would need to sequentially load all pages until you get to your desired position, so instead the better strategy is to start loading from where you want the user's scroll position to start, then let paging prepend pages as they scroll back up.

dlam
  • 3,547
  • 17
  • 20
  • But what if we have the necessity to actually jump to a page? Like if a detail page is a view pager with paging and we need to go to the correct index of the viewPager?? – alessandro gaboardi Jan 26 '21 at 08:35
  • There are two ways to perform a "jump" because paging makes no guarantees about sizes of pages and no way to compute a key to load with based on just an offset. – dlam Jan 27 '21 at 00:49
  • The first way is to enable placeholders and jumping in `PagingSource`, meaning you know the full count of the entire dataset and will pass that as `placeholdersBefore` and `placeholdersAfter` in initial load. Then after scrolling past `PagingConfig.jumpThreshold`, it will essentially trigger paging to start loading from scratch there via refresh. You then need to implement `PagingSource.getRefreshKey()` to return the correct load key to load around the user's position, which is where you tell paging how to map position to load key. – dlam Jan 27 '21 at 00:53
  • See: https://developer.android.com/reference/kotlin/androidx/paging/PagingConfig#jumpThreshold:kotlin.Int and https://developer.android.com/reference/kotlin/androidx/paging/PagingSource#getRefreshKey(androidx.paging.PagingState) – dlam Jan 27 '21 at 00:54
  • The second way to perform a "jump" is by invalidation via remote calls, this is done by essentially clearing the backing dataset and inserting new data to load from based on some external signal. Invalidation triggers the same refresh call above, but in this case you don't know the size of your dataset and you want to "jump" based on something other than scroll distance. This doesn't necessarily mean using `RemoteMediator`, it depends on where you want your "jump" signals to come from. – dlam Jan 27 '21 at 00:57
  • In most cases, people usually mean the "fast-scroll" behavior where you essentially want to skip loading some pages and start again somewhere else, preserving maxSize based around the new position - this is the first case, but it requires having a counted dataset so that you can actually scroll into placeholders to trigger the "jump" and being able to map an arbitrary position to a key. – dlam Jan 27 '21 at 00:58
  • Thank you, I'll try this as soon as i can! – alessandro gaboardi Jan 27 '21 at 08:31
  • Since we're here, i didn't find a way to make the loading view span 2 columns in a gridlayoutmanager, i set a custom viewtype in loadstate adapter but it doesn't translate in gridlayoutmanager span lookup – alessandro gaboardi Jan 27 '21 at 08:34
  • Can you file a bug for this with your sample project? https://issuetracker.google.com/issues/new?component=413106&template=1096385 – dlam Jan 28 '21 at 06:58