I am using the Paging library from Android Jetpack to have a paged loading behavior in my RecyclerView. I'm loading directly from network so I don't have any intermediate in-memory cache or database. Whenever something changes I call invalidate() on DataSource (in my case PositionalDataSource) so that the list is refreshed.
What I need is very simple thing - once I call invalidate() the recycler view is fully cleaned up and shows empty data. I need the recycler view to keep the old data and update normally once the new data comes in. In most of the cases the update might be very small, like a button color change in couple of rows, it looks ugly when the RecyclerView shows empty content for couple of seconds while I'm loading data from backend.
Can this somehow be done or is there a conceptual limitation of the current Paging library architecture forcing me to implement my own caching?
calling notifyDataSetChanged instead of invalidate may help as a simple solution.
Related
Basically I have a paging data flow collected in a composable function:
val list = state.listFlow.collectAsLazyPagingItems()
Each item on the list has a call-to-action button that will enable/disable the view and update the UI of the corresponding item.
My question is, how can we update the visual state of the item without the need for calling refresh on the PagingData and therefore re-querying the API/database for updated data?
Also if user has scrolled through 5 pages or more I don't want to reload the whole content, changes can be local.
Any clues on how to achieve this?
This is almost impossible for Paging3, which requires immutable lists. See https://issuetracker.google.com/issues/160232968.
This problem bothered me for months and finally I decided to abandon Paging3 library and write my own paged list to avoid all these weird features. Most of the complexity of Paging3 is because it wants to encapsulate the paged list in one library, which needs the view layer and the model layer to work together.
This is the paged list I implemented: https://gist.github.com/FishHawk/6e4706646401bea20242bdfad5d86a9e
If your project does not have a deep dependency on the paging3 library, I highly recommend you try doing this.
I would like to add some item in current paging data which already contains items. And shown in the list adapter.
I have tried to insertHeaderItem. But, when adding second item. Header is getting replaced by second item. I want to keep all item in the list. and update that list every time when i add new item.
paingData
.insertHeaderItem(item = sampleViewEvents.comment)
.let {
getCommentList.value = it
}
I doesn't want to call an API to refresh the whole list. It can leads a performance issue.
Thanks in advance
The correct way to add / modify items with Paging is to update the backing dataset and .invalidate(), refreshing the list. This maintains a single source of truth and allows Paging to be aware of the changes you've made.
For performance, you can cache your data into a middle DB / in-memory layer, and load items from network via RemoteMediator. If you do this (which you should if you are concerned about performance), the reload becomes quite trivial. See: https://developer.android.com/topic/libraries/architecture/paging/v3-network-db
If you are interested in updating a specific page, you can follow this FR: https://issuetracker.google.com/160232968.
To be clear, you MUST go through the invalidate loop to update the items loaded by Paging. Not doing it this way is currently completely unsupported. It is the only way to make Paging aware of the changes you've made.
In my Android app i'm showing data in a RecyclerView using Room and the Paging library.
My implementation is quite similar to the example in the AsyncPagedListDiffer docs.
The flow is the following:
Data is changed in the database
A corresponding Observer passes the changes to the Adapter:
myLiveData.observe(viewLifecycleOwner, Observer {
myAdapter.submitList(it)
})
The AsyncPagedListDiffer calculates the diff and updates the list accordingly
My problem is the performance hit of step 3.
Even if i insert just one single item to the top of the list, the differ have to check all of the items (which is quite inefficient, especially with larger datasets), whereas a simple notifyItemInserted(0) call would be sufficient.
Is there a way around this behavior?
For example, can i tell the differ that it doesn't have to check all of the items? Or any other solutions to this?
I'd really appreciate any advice.
In the beginning we had listViews. As a developer, we had to recycle and reuse the views to have a fluid experience.
Then, came the recylclerviews. Now, all the recycling heavy lifting is managed by android library itself.
Using pagination, an infinite recycler view can be implemented, which loads the data when needed.
But there is one problem I am still facing in infinite recyclerview. How is the data in the adapter managed?
In most of the infinite scroll implementations of recyclerview, the new data is appended to the original data. This makes the size of data set ever increasing.
Why cant dataset itself behave like recyclerview and recycle its data, instead of appending? (Like a circular queue).
How can one manage the positions of itemviews, when the dataset is a circular queue. Is it unnecessary and yields too little performance improvement? Am I missing some design pattern?
It would be possible to clear data already loaded, but this way you have to load data not only for "bottom" views, but for "upper ones" too. So user wants to back to previous data and he needs to load that data again, that's the problem.
There could be more work about notifying data set changed in recyclerView.
You can implement it this way, but remember about pagination and how it is implemented - for example limiting data in SQL statements standard way can output different data each call, so user backing to previous data can see other results! Check Twitter pagination for one of the way to achieve same results each time.
Pros:
less data in memory
Cons:
more work to write the code
more data loading for users (more internet usage, more loading times - when users wants back to previous data)
pagination has to be designed more carefully
I'm using recycler view with grid view (every item contains a grid) with thumbnail images after adding images in view it start uploading, and i need to change some values (status) in model at the time of start and finish upload.
What I'm currently doing is change values in model and call notifyDataSetChanged, but it causes to slow down application (hang some times) because it updating every child of list :(
Can any one help me with this?
Call notifydatasetchanged() for particular Gridview adapter only. Don't call notifydatasetchanged() for complete recyclerview adapter.
Try setting it again to the adapter.
gridview.setAdapter(your adapter)
-passing your new list to your adapter.
I believe notifyDataSetChanged updates all of your values regardless if they have a change or not that is why it is slow. I suggest you try using notifyItemChanged(int position) instead.
According to recyclerview docs this is what notifyDataSetChanged does:
This event does not specify what about the data set has changed, forcing any observers to assume that all existing items and structure may no longer be valid. LayoutManagers will be forced to fully rebind and relayout all visible views.
Old question but similar to what I'm experiencing.
RecyclerView is usually incredibly fast when changing list details. But manipulating a lot of images can really slow it down if you're not careul.
I'd recommend you try removing the images and repeat it so you can see if that is just as slow. I suspect this will be a lot faster.
If so, make sure you're handling the images off the UI thread. The Android docs recommend you use a library such as Glide which also handles sub-sampling the image to make sure it's the right size.
Hope that helps!