Skip to content
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

How to delete/remove PagedListAdapter item #281

Closed
faris-jameel opened this issue Jan 10, 2018 · 44 comments
Closed

How to delete/remove PagedListAdapter item #281

faris-jameel opened this issue Jan 10, 2018 · 44 comments
Labels

Comments

@faris-jameel
Copy link

Currently I am using Android Architecture Components for App development everything is working along with paging library Now I want to remove recyclerview Item using PagedListAdapter to populate this we required to add a data source and from data source list is updating using LiveData no I want to remove a item from list notifyItemRemoved() is working from PagedList I am getting this exception:

java.lang.UnsupportedOperationException

java.util.AbstractList.remove(AbstractList.java:638)

@sopherwang
Copy link

I had same issue.

@faris-jameel
Copy link
Author

@JiajunWong did you find any solution?

@tuinui
Copy link

tuinui commented Feb 6, 2018

i got this problem to when i try to Collections.sort

@guness
Copy link

guness commented Feb 19, 2018

I have created some custom adapter to handle this case(only a part of it actually). Luckily I was supposed to add on top of current list, so following solution only supports adding to top. However you can try to customize it.

https://gist.github.com/guness/df12d8cc4f595af1395f4a1f5bca5f00

In addition, I think some kind of merging support for the data sources would be a nice to have feature for pagination library.

@junki-kim
Copy link

i had same issue

@shashankkapsime
Copy link

shashankkapsime commented Jun 19, 2018

@yigit Can anyone answer this issue please.

@Tenkei
Copy link

Tenkei commented Jun 24, 2018

Already had this discussion here:

If you have a collection shared w/ a RecyclerView, that collection CANNOT be modified w/o telling RecyclerView. So all modification & notifications needs to happen on the main thread and in the same call stack.

We could technically create a DataSource API that allows passing such partial changes but then we would need to log all of them and re-deliver to the RV on the main thread. The issue w/ that approach is that, if you have a RecyclerView that is stopped (a.k.a back stack), it will not (should not) receive any updates so PagedList would be keeping this potentially long list of items and re-apply on main thread for each observer (again some observers may have received some events).

This greatly complicates the problem, which is why we go w/ a single list.

Also, none of those optimizations would work w/ sqlite (so yea, that had a part). You can easily create a DataSource that can take a previous list and keep modifications on it, but still return it as a list. In other words, implement that tracking logic in your DataSource which would not need to deal w/ RecyclerView's thread restrictions.

TL;DR: To update a pagedList you have to create a new list, this is how room update data and you have to do the same if you want to update your list.

@CarGuo
Copy link

CarGuo commented Jun 28, 2018

I try this after delete local data

liveModel?.pageList?.dataSource?.invalidate()

@adam-hurwitz
Copy link

adam-hurwitz commented Sep 1, 2018

After re-reading the documentation under Consider How Content Updates Work it appears the only way to have realtime updates is via implementing Room with the PagedList: If you're loading data directly from a Room database updates get pushed to your app's UI automatically.

I'm planning to connect my Firestore queries to Room in order to be able to remove items from my PagedList without having to invalidate the DataSource and reload the entire RecyclerView.

@abhinav272
Copy link

@AdamSHurwitz
If you connect your server data with Room to create PagedList from it, even then when you delete an item from your local DB your DataSource will be invalidated automatically and you will get another version of PagedList from Room in your onChanged()
Am I right?

@adam-hurwitz
Copy link

adam-hurwitz commented Sep 15, 2018

@abhinav272 This is not the case. When an individual item in Room is added or modified the PagedList updates the corresponding entry rather than refreshing all of the data in the component. Therefore I'm able to update Room with Firestore data when it changes and allow Room + PagedList to handle the updates on individual cells. As long as Room is updated of the change the PagedList will animate and update/add/remove the item modified.

Conversely, if Firestore data was connected directly to the PagedList the entire data set would need to be invalidated / refreshed since the PagedList cannot automatically recognize individual changes from Firestore.

@abhinav272
Copy link

@AdamSHurwitz
Do you get a callback in onChanged() when you update the data in Room??
If so, that means Room has invalidated the DataSource and has provided new one with PagedList containing new data.

When I create a DataSource which is fetching data from either Room or Network, it gives me a callback in onChanged() only once when the PagedList gets created (upon creation of DataSource) and when the pages are loaded it automatically gets displayed on UI..

Make sense?

@adam-hurwitz
Copy link

@abhinav272 - May you specify which onChangedd() method you are referring to?

I don't make Room updates directly. I update Firestore's database. With Firestore when a piece of information changes the Firestore listener will send an update. I listen for that update and inform Room of the change using a LiveData object. This makes it easy to keep both my backend Firestore and front-end Room data synced with minimal work.

@Dilip23
Copy link

Dilip23 commented Oct 2, 2018

@abhinav272

I had the same kind of issue!!!
I am building an app that receives data from network API which gets chached in Room DB. Now if i have to delete an item ,I send a request to delete an item in Remote DB(Network) and if the response is 204 , I delete an item in the Room , So then the Room DB creates a new PagedList and notifies the UI.... Right??

Or else Do we have to implement in any other way???

@abhinav272
Copy link

@Dilip23 yeah, this looks fine.

@Dilip23
Copy link

Dilip23 commented Oct 3, 2018

@abhinav272

It worked !!! Great!!!

@adam-hurwitz
Copy link

@abhinav272 - This is how I am currently implementing it. When I remove an item from Firestore it also updates my Room Db.

@roby222
Copy link

roby222 commented Jan 11, 2019

@faris-jameel if I understood correctly the question...
If you use the PagedListAdapter, you don't need to call any notifyItemRemoved() or similar.
So, if you delete your item from Room, the recycler adapter will be updated automatically

@sonalchopra-vvdn
Copy link

@AdamSHurwitz @abhinav272 I have also implemented same way. Whenever I update the room DB, UI is notified with the new list and I call submitList() method. Whenever an item is added at last no problem, but if an item added at the top(as I am querying sorted list from DB) my whole list flickers(the whole list loaded again and whole list UI refreshed), same with remove, if I remove the last item its fine and only that item moves/affected but when top item, whole list seems loading again.

@abhinav272
Copy link

@sonalchopra-vvdn
There may be a problem with your DiffUtil.ItemCallback<>
Fyi, whole list is returned Everytime whether you add/remove/update any item at any position, but the PagedListAdapter is smart enough to draw only those items which are new or changed, it skips re-drawing items which are same and this logic is implemented in your DiffUtil.ItemCallback<> overridden methods.

@roby222
Copy link

roby222 commented Jan 21, 2019

I made a sample using PagedListAdapter https://github.com/roby222/recyclerViewSample
I'm currently work on that because the page size settings doesn't work (I setted 20 items at a time, but I receive all db items!)

@abhinav272
Copy link

@roby222
By default PagedListBuilder has placeholders set to true, so you may receive whole list but after 20 items all items will be null.
If you want you can set placeholders to false.

@alexandru-calinoiu
Copy link

I would love to see an example of this using anything else then room.

@parcool
Copy link

parcool commented Aug 13, 2019

I need a sample that without room too.

@frog1014
Copy link

need a sample that without room too.

@mochadwi
Copy link

I have created some custom adapter to handle this case(only a part of it actually). Luckily I was supposed to add on top of current list, so following solution only supports adding to top. However you can try to customize it.

https://gist.github.com/guness/df12d8cc4f595af1395f4a1f5bca5f00

In addition, I think some kind of merging support for the data sources would be a nice to have feature for pagination library.

@guness Maybe you want to update the class with PagedListAdapterHelper

@dlam
Copy link
Contributor

dlam commented Jun 19, 2020

We're discussing options to better support granular updates in Paging3, but currently to delete / remove an item you'll need to update the backing db, then invalidate your DataSource / PagingSource. Room handles propagating invalidation for you, but if you're not using Room you'll need to manually call DataSource.invalidate(). Your DataSouce.Factory should then generate a new instance of DataSource to load the updated data.

@dlam dlam closed this as completed Jun 19, 2020
@dlam
Copy link
Contributor

dlam commented Jun 19, 2020

In Paging3, we also provide APIs to transform a PagingData (new PagedList) as we expose PagingData as a Flow. You can theoretically combine / filter / map / etc, in whatever way your heart desires, but the backing mechanism is still the same. We're looking into ways to provide more granular updates without invalidating the whole list as it's a common use case, but Paging3 is still very early in alpha.

@ishdemon
Copy link

so there is just no way to update/modify a pagedlist item without invalidating the datasource if i am not using room. -_-

@dlam
Copy link
Contributor

dlam commented Feb 22, 2021

Actually even with Room it works the exact same way, Room just handles the invalidation for you. Any modifications you make also need to update the source of truth for paging, because reloading the page should always keep the updates you make.

For a Flow / stream based approach which allows Paging to subscribe to individual item / page updates that do not require the invalidation loop please follow / +1 this bug: https://issuetracker.google.com/160232968

@309152665
Copy link

I need a sample that without room too.

@ahmednabeel1991
Copy link

Hello All,

After Allot of search I fixed this bug. The answer is here bellow

mainListAdapter.snapshot().toMutableList().apply { removeAt(position) }
            mainListAdapter.notifyItemRemoved(position)
            
            Cheers!!

@guness
Copy link

guness commented Jul 12, 2021

This answer assumes that the list used in mainListAdapter is mutable. However, it does not have to be one. So the solution may start failing on another version.

@dlam
Copy link
Contributor

dlam commented Jul 12, 2021

Hello All,

After Allot of search I fixed this bug. The answer is here bellow

mainListAdapter.snapshot().toMutableList().apply { removeAt(position) }
            mainListAdapter.notifyItemRemoved(position)
            
            Cheers!!

This won't work, you must remove items through Paging via invalidation, otherwise Paging will not know to carry your item removal through page reloads, refresh, config changes, etc.

@309152665
Copy link

Hello All,

After Allot of search I fixed this bug. The answer is here bellow

mainListAdapter.snapshot().toMutableList().apply { removeAt(position) }
            mainListAdapter.notifyItemRemoved(position)
            
            Cheers!!

thanks , but the network data with pagingdata , snapshot is the pagingdata's copy. snapshot.toMutableList() , the mutablelist is the snapshot copy.

@309152665
Copy link

This answer assumes that the list used in mainListAdapter is mutable. However, it does not have to be one. So the solution may start failing on another version.

ok , thanks

@ahmednabeel1991
Copy link

Hello All,
After Allot of search I fixed this bug. The answer is here bellow

mainListAdapter.snapshot().toMutableList().apply { removeAt(position) }
            mainListAdapter.notifyItemRemoved(position)
            
            Cheers!!

thanks , but the network data with pagingdata , snapshot is the pagingdata's copy. snapshot.toMutableList() , the mutablelist is the snapshot copy.

If you are using only network call with pagging then this solution will work because you will remove Item locally after network api call . Let say I Call retrofit call first for removing the item and on success response of that Api Call we will remove that particular item from snapshot.

@309152665
Copy link

Hello All,
After Allot of search I fixed this bug. The answer is here bellow

mainListAdapter.snapshot().toMutableList().apply { removeAt(position) }
            mainListAdapter.notifyItemRemoved(position)
            
            Cheers!!

thanks , but the network data with pagingdata , snapshot is the pagingdata's copy. snapshot.toMutableList() , the mutablelist is the snapshot copy.

If you are using only network call with pagging then this solution will work because you will remove Item locally after network api call . Let say I Call retrofit call first for removing the item and on success response of that Api Call we will remove that particular item from snapshot.

snapshot is copy , delete from snapshot , the pagingData not change.

@ahmednabeel1991
Copy link

Hello All,
After Allot of search I fixed this bug. The answer is here bellow

mainListAdapter.snapshot().toMutableList().apply { removeAt(position) }
            mainListAdapter.notifyItemRemoved(position)
            
            Cheers!!

thanks , but the network data with pagingdata , snapshot is the pagingdata's copy. snapshot.toMutableList() , the mutablelist is the snapshot copy.

If you are using only network call with pagging then this solution will work because you will remove Item locally after network api call . Let say I Call retrofit call first for removing the item and on success response of that Api Call we will remove that particular item from snapshot.

snapshot is copy , delete from snapshot , the pagingData not change.

Try this with the same code it is working.

@309152665
Copy link

Hello All,
After Allot of search I fixed this bug. The answer is here bellow

mainListAdapter.snapshot().toMutableList().apply { removeAt(position) }
            mainListAdapter.notifyItemRemoved(position)
            
            Cheers!!

thanks , but the network data with pagingdata , snapshot is the pagingdata's copy. snapshot.toMutableList() , the mutablelist is the snapshot copy.

If you are using only network call with pagging then this solution will work because you will remove Item locally after network api call . Let say I Call retrofit call first for removing the item and on success response of that Api Call we will remove that particular item from snapshot.

snapshot is copy , delete from snapshot , the pagingData not change.

Try this with the same code it is working.

the code is working , but you can try more items adapter ,
device-2021-07-14-174201
such as this record , over a screen items , you delete the first one , scroll and look , the items in last , you can find some items has disappear.
image

Screenrecorder-2021-07-14-17-45-59-455.mp4

@rajangupta-dew-beauty
Copy link

I have implemented PagingDataAdapter in my project and required multiple filtering and sorting. so any one could suggest me achive this.

@rahul4452
Copy link

rahul4452 commented Jul 6, 2022

Is there any workaround for removing item from PagingDataAdapter ? @309152665

@Reypak
Copy link

Reypak commented Jul 6, 2022

.toMutableList().apply

please help convert to java

@dharamveer-appyhigh
Copy link

dharamveer-appyhigh commented Sep 11, 2022

I try this after delete local data

liveModel?.pageList?.dataSource?.invalidate()

what if we are using cachedIn Flow?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests