PagedListAdapter jumps to beginning of the list on receiving new PagedList

[亡魂溺海] 提交于 2019-12-03 08:16:54

You should use a blocking call on your observable. If you don't submit the result in the same thread as loadInitial, loadAfter or loadBefore, what happens is that the adapter will compute the diff of the existing list items against an empty list first, and then against the newly loaded items. So effectively it's as if all items were deleted and then inserted again, that is why the list seems to jump to the beginning.

You're not using androidx.paging.ItemKeyedDataSource.LoadInitialParams#requestedInitialKey in your implementation of loadInitial, and I think you should be.

I took a look at another implementation of ItemKeyedDataSource, the one used by autogenerated Room DAO code: LimitOffsetDataSource. Its implementation of loadInitial contains (Apache 2.0 licensed code follows):

// bound the size requested, based on known count final int firstLoadPosition = computeInitialLoadPosition(params, totalCount); final int firstLoadSize = computeInitialLoadSize(params, firstLoadPosition, totalCount);

... where those functions do something with params.requestedStartPosition, params.requestedLoadSize and params.pageSize.

So what's going wrong?

Whenever you pass a new PagedList, you need to make sure that it contains the elements that the user is currently scrolled to. Otherwise, your PagedListAdapter will treat this as a removal of these elements. Then, later, when your loadAfter or loadBefore items load those elements, it will treat them as a subsequent insertion of these elements. You need to avoid doing this removal and insertion of any visible items. Since it sounds like you're scrolling to the top, maybe you're accidentally removing all items and inserting them all.

The way I think this works when using Room with PagedLists is:

  1. The database is updated.
  2. A Room observer invalidates the data source.
  3. The PagedListAdapter code spots the invalidation and uses the factory to create a new data source, and calls loadInitial with the params.requestedStartPosition set to a visible element.
  4. A new PagedList is provided to the PagedListAdapter, who runs the diff checking code to see what's actually changed. Usually, nothing has changed to what's visible, but maybe an element has been inserted, changed or removed. Everything outside the initial load is treated as being removed - this shouldn't be noticeable in the UI.
  5. When scrolling, the PagedListAdapter code can spot that new items need to be loaded, and call loadBefore or loadAfter.
  6. When these complete, an entire new PagedList is provided to the PagedListAdapter, who runs the diff checking code to see what's actually changed. Usually - just an insertion.

I'm not sure how that corresponds to what you're trying to do, but maybe that helps? Whenever you provide a new PagedList, it will be diffed against the previous one, and you want to make sure that there's no spurious insertions or deletions, or it can get really confused.

Other ideas

I've also seen issues where PAGE_SIZE is not big enough. The docs recommend several times the maximum number of elements that can be visible at a time.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!