-
Notifications
You must be signed in to change notification settings - Fork 730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sticky headers displays wrong header or crashes after dataset change #1211
Comments
Thanks for the detailed bug report. Sticky headers were contributed by an external person and I am not too familiar with the code and don't maintain it myself, but you or anyone else are welcome to submit a PR for a fix. |
A simple fix would be to request a full header positions scan on each adapter change which would not be the most efficient. |
@cbeyls thanks for investigating this issue. |
@cbeyls can you share gist of modified version of |
My version is heavily modified and doesn't depend on Epoxy anymore. For example, I'm passing the adapter directly in the constructor. |
I took a look into @cbeyls 's code.
And that's it. The key changes that ensure the sticky-header-list stay correct. The generation/update was just like the ones that did in current However, It turns out that the script change-mark is quite limited, causing it ran more "whole-refresh" than needed. For example, if I insert/remove/change more than 2 times of the item list, the LayoutManager might thus refresh the whole list, making it difficult to keep the list at the same position after changes. Because of the problem above, I don't think this would be a prefect solution (for a PR). I'm still investigating on how to prevent (or to improve) that problem. |
In my personal opinion, I came up with a thought: if this issue happens because of the sticky-header-list generated incorrectly, can't we just make it simpler? Like, change it into a This will be my current goal of investigation. I'd let you know if I succeed. |
@samuelchou Any success with the investigation? |
Nope. Been busy since then. 😢 |
Hello ! I reckon this is the same issue as this one, is it on the todo list yet ? Thanks ! |
1. Make sticky-header-list generation/update into a late-time operation, which is called ONLY in `onLayoutChildren`. 2. Mark sticky-header-list changes in the `HeaderPositionsAdapterDataObserver`: `onChanged`, `onItemRangeInserted`, `onItemRangeRemoved`, and `onItemRangeMoved`. Original solution from [cbeyls's custom StickyHeaderLinearLayoutManager](https://gist.github.com/cbeyls/db4351870e493a817bf0f4fd84e2b598). More information from [thread of issue airbnb#1211](airbnb#1211).
I did a little bit more research on it.
For example, consider an index list
when inserting a new (non-SH) item at index
and situation become more complex when including SH and more :
So far, I think Any suggestion or idea is welcome. (I'm also looking forward to someone else fixing this problem 😆 ) |
I just have a try,problem seems to be solved. |
StickyHeaderLinearLayoutManager
does not handle adapter dataset changes correctly.Specifically, it doesn't handle properly the case where a set of changes notifications includes an insert followed by one or more deletes or moves. This causes the wrong view to be used as sticky header in some cases, and in rare cases it can also cause an out of bounds error because the code tries to access data outside the range of the adapter.
The flawed logic is located in the child class
HeaderPositionsAdapterDataObserver
. As long as items are deleted or moved, everything works fine. But whenonItemRangeInserted()
is called, there is a problem: the code tries to access the adapter immediately to check if there are headers in the new inserted elements, but instead it must wait for the other adapter updates to be dispatched before accessing the adapter data to be able to compute the adapter positions correctly.Because adapter updates are asynchronous, multiple calls to
notify*
can be done in a row for a single change of adapter data. It's only after that, during the next layout pass that the adapter data can be accessed.Here is a simple example to illustrate the issue:
notifyItemInserted(4, 1)
immediately followed bynotifyItemDeleted(0, 1)
onItemRangeInserted()
is called,HeaderPositionsAdapterDataObserver
inStickyHeaderLinearLayoutManager
will immediately try to access the adapter element at position4
to check for new headers. But this position is out of range: the list only contains 4 elements. The adapter needs to wait for the following call toonItemRangeRemoved()
to be able to compute the adapter positions correctly. The adapter should only be accessed asynchronously during the next layout pass.Because of this, sticky headers are unstable and cannot be used with
DiffUtil
. OnlynotifyDataSetChanged()
works reliably.The text was updated successfully, but these errors were encountered: