Injecting items into PagedListEpoxyController makes RecyclerView jump upon update
See original GitHub issueWe have a list of items that come from the database. Based on their date we generate header models that we insert in the list using addModels
.
We scroll for a bit, up to a point where the last item of the first page is at half of the screen (this means the second page will be loaded). Now we update some item in the database to trigger a new PagedList
. Upon submitting this new PagedList
to epoxy, AsyncPagedListDiffer
will diff the items and update the list. This new list will not start at position 0 (that’s how paging library works). This means that the initial items will be removed from the RecyclerView
. Without adding extra models, the RecyclerView
will be able to keep it’s position. You will see exactly the same items on screen. As soon as we add extra items, the RecyclerView
isn’t able to keep the same position on screen and we see a jump when it removes the initial items.
Now I have two untested theories for this:
-
It’s because only the item list gets diffed so the
RecyclerView
doesn’t account for the extra items height (is this right?). In that case we have to diff the model list instead of the item list. -
It’s because of:
override fun onModelBound(
holder: EpoxyViewHolder,
boundModel: EpoxyModel<*>,
position: Int,
previouslyBoundModel: EpoxyModel<*>?
) {
// TODO the position may not be a good value if there are too many injected items.
modelCache.loadAround(position)
}
Somehow, the controller would have to take the additional injected items into account.
I’m more inclined towards theory 1. But I don’t know if the premise for that option is valid.
I’ll try to build a small project to replicate the issue. Maybe @yigit can shed some light on this?
Thanks
Issue Analytics
- State:
- Created 5 years ago
- Reactions:2
- Comments:8 (4 by maintainers)
This is likely related to the google issue below. See the comments at the bottom of that issue.
https://issuetracker.google.com/issues/123834703
Long story short, if you are using an ItemKeyedDataSource, on invalidation(e.g., update on the list), the current position on the screen will be ignored when computing the items/pages to load. This can lead to “jumps” to other parts of the list as the paging library will attempt to load pages that are not the ones in the current screen context.
I consider this a bug in Android’s paging library. Everyone using ItemKeyedDataSource will eventually run into this issue with no recourse other than overriding complex library code.
If you are to chase this down, find implementations of the DataSource.InvalidatedCallback interface and notice that most of them boil down to a
initializeKey = PagedList.getLastKey()
followed by the instantiation of a new PagedList withsetInitialKey(initializeKey)
. ThegetLastKey()
method effectively runs the code below, leading to “jumps” as the current position is ignored.@yigit Can you provide some input into this issue? The participants on this issue have provided a fair amount of detail on why this issue happens along with steps to reproduce. I understand that there is a fair amount of changes coming up in Android Pagination(coroutines, etc) and it will be great that an answer to this issue is provided as part of this iteration. Thank you for your help.