-
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
Fix infinite loadBefore calls #817
base: master
Are you sure you want to change the base?
Conversation
Adjust last position if inserted item is before last position. Fixes airbnb#816 and airbnb#621
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced by this approach, it doesn't seem to address the root issue, which is "why does telling the paged list to load around an index (which should be already loaded) cause it to insert new data?"
Once we've loaded around a position the data should be inserted, so calling to load at the same index again should be a no-op. This churn points to the page size not being large (which is the key recommendation in #621)
I noticed in your sample code that page size is only 5. This also sets the prefetch distance to 5. I don't know how many items are on your screen, but it seems like the page size is much to small. It should be several times (maybe 10x?) the expected number of items on screen (according to the PagedList.Config javadoc). Have you tried increasing your page size?
Of course, it would be nice to have robust behavior even when config sizes are not set correctly. Given that the infinite loop involves the getModels -> triggerLoadAround
path, it may be simplest and cleanest to remove or modify how triggerLoadAround is called from getModels.
I'm not clear on why we need to call triggerLoadAround from there in the first place. It seems unnecessary, but may be needed for some edge case of loading data. I would recommend looking into figuring out why/when that is needed, and possibly removing it or limiting when it is called.
@@ -97,6 +97,11 @@ internal class PagedListModelCache<T>( | |||
(0 until count).forEach { | |||
modelCache.add(position, null) | |||
} | |||
lastPosition?.let { | |||
if (position < it) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if it + count
is greater than position? you compare these two but don't look at the value of count
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it matter if it + count
is greater than position?
If lastPosition
was 5 and we just inserted 50 items before 5th position e.g. onInserted(position = 0, count = 50)
then your "lastPosition" MUST be adjusted to 50 + 5.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lastPosition
is the last index that was bound, not the last index that was added. They are too different things, and using the same property to represent two different things is confusing and dangerous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lastPosition
can be renamed to nextLoadAroundPosition
. When we insert new data in the list before this position, this variable no longer holds true. so renaming it may help. This way nextLoadAroundPosition
acts like a command argument that should be used in next call to loadAround
. This is exactly how it is being used now btw.
@elihart Lets assume that LoadAfter Case: LoadBefore Case: This is exactly what is happening here. Page size doesn't matter. I have tried it with very large page size as well. So the only solution is to detect if items are inserted before last loadAround position and adjust for that. |
@mwajeeh Thanks for explaining. Two questions:
|
The sample code that I have attached is very simple and is almost identical to epoxy paging sample app. Method to reproduce this behaviour is also very easy. Running that sample will clear up lot things and you might find something that I have missed. |
I understand data can load in both directions, but at index 0 there should not be any data to load before, so why does the paging library still do so?
Why is this infinite loop possible once data is already loaded? Once data at that position is loaded, the |
@elihart How can we assume that at local 0th index there is no more data to be loaded? Let's assume you have a
When user scrolls up,
Now ideally because user hasn't reached to the top yet, epoxy shouldn't be invoking |
We faced exactly same issue and it's quite critical for us. @elihart could please clarify if there is any decision about the fix? Is it going to be approved and merged soon? |
@tusacheva-flo I ended up changing my approach to pagination after this issue. I am now using |
Adjust last position if inserted items are before last position.
Fixes #816 and #621