After DataSource.Invalidate() new PagedList has only one page
Asked Answered
L

2

11

I have a list with pagination which I implemented using Paging library. Items on this list can be modified (changed/deleted). According to official documentation, I'm first changing in-memory list cache from which my DataSource gets pages and after that calling datasource.invalidate() in order to create new pair PagedList/DataSource:

If you have more granular update signals, such as a network API signaling an update to a single item in the list, it's recommended to load data from network into memory. Then present that data to the PagedList via a DataSource that wraps an in-memory snapshot. Each time the in-memory copy changes, invalidate the previous DataSource, and a new one wrapping the new state of the snapshot can be created.

It works and looks WELL if user modifies items on first page.

However, if user is on page two or further during datasource.invalidate() he will be thrown at the end of the first page.

Debugging shows this happens because new PagedList has only first page when it's submitted to PagedListAdapter.submitList. Adapter compares old and new lists and removes all items not from first page. It happens always but not visible for user if he is on the first page.

So to me, it looks like new pair PagedList/DataSource have no idea about number of pages which fetched previous pair and datasource.invalidate() doesn't fit for the situation in docs. Behavior that I see acceptable for cases then user updates all list (like swipe-to-refresh) but not

an update to a single item in the list

Has anybody faced such issue or somehow archived things I want? Maybe I'm missing some trick which helps me to get new PagedList already with all pages.

For clarification: library version 2.1.0. Custom PageKeyedDataSource based on in-memory cache and remote servise (No Room)

Linter answered 23/2, 2019 at 22:30 Comment(5)
So what you actually want to achieve. Are you want to get all items from loaded pages?Graphomotor
@HussnainHaidar the main goal is to have editable list implemented with Paging library. The thing that I think help me where I'm stuck now - somehow make new DataSource after invalidation to load all pages that old one did and only after that emit new PagedList so I could submit it to the adapter.Linter
Are you using live data to observe the list?Graphomotor
Yes, "all by the book". Just found very similar question The guy from answer explains problem similar to me but solution and ideas don't work. There is no additional data in custom PageKeyedDataSource except page_key and page_size.Linter
Yes I faced same problem when data order is changed from backend on some pages then I have to invalidate data and update all data then bring user to last pos, but I could not achive it till now even with paging 3. This is my tries if you interested:#70706121Interflow
L
6

I want to share my research in case anybody is interested:

  1. Issue ("lack of feature") is known, at least I've found the couple related discussions on official tracker one two
  2. If you are using PositionalDataSource or ItemKeyedDataSource you should dig into the direction of requestedStartPosition/requestedInitialKey from initial params as this answer says. I didn't have much time to build the whole solution but those params are indeed different for initial load after invalidation

About my case : PageKeyedDataSource. Here you can read that there is no similar to requestedInitialKey params in this type of data source. Still, I found a solution which fits me, very simple, although, feels like a dirty trick:

When loadInitial() is called after invalidate() in-memory cache returns all already loaded pages instead of just first one. At first I was worry that something will break if, for example, requestedLoadSize is 5 but the result is 50 items list but turns out it's just a hint and it can be ignored. Just don't forget to pass nextPageKey which corresponds to the last cached page and not the first one.

Hope it will help

Linter answered 3/3, 2019 at 12:9 Comment(2)
First of all thanks for this post, it's steering me in the right direction i think. Second, you can't use requestedInitialKey because that will be from the last page that was loaded and if the user scrolled say back to the middle it will have lost where the user was. Also if you scroll to the end the list will load no new items and that's never good. Still trying to find a way for this to work. Right now thinking maybe the base class we have that is a sealed class is defeating the equals from the child data classes.Stationmaster
I'm not sure if this is going to help you, but when I was looking for a solution for a very similar issue I saw somewhere mentioned that the loadInitial must be larger than the number of items on the screen. Otherwise it wouldn't be able to trigger follow up calls.Dolt
G
0

With observable method you will only get first page list items....if you want to edit other items you can get that list by adapter.currentlist method.

Example:

 private fun list():MutableList<String>{
    val list = mutableListOf<String>()
        for (value in videosAdapter.currentList.orEmpty()) {
            val abc = value.snippet.resourceId.videoId
            list.add(abc)
        }
    return list
}
Graphomotor answered 24/2, 2019 at 11:40 Comment(1)
I meant editable list from the user's perspective. After I will edit data from a list that created in your way I would still need somehow to pass it to PagedListAdapter and it's not possible without DataSource.Factory. As the documentation says : "A new pair of PagedList / DataSource must be created if an update occurs, such as a reorder, insert, delete, or content update occurs".Linter

© 2022 - 2024 — McMap. All rights reserved.