I have a recycler view with a delete button for every item,and the data for the recycler view is a Live Data list.
Basically im observing the list and when i delete an item i just pass the adapter again to the recycler view with the new list in order for the list to update,like this
viewModel.loadBasketItems().observe(viewLifecycleOwner, {
adapter = BasketFragmentAdapter(it, viewModel, requireContext())
recycler.adapter = adapter
})
My first problem with this is that the image jumps to the top of the list every time i delete an item,because the list is created again completely
My second problem with this is i don't think this is very efficient.
What's the best method to update the recycler view after you change something
You shouldn't be resetting the adaptor like that. Keep the adaptor the same, but call notifyDataSetChanged(). This tells the adaptor its data has changed, which will tell the recycler view to redraw itself. What you're doing makes the recycler view assume it has a whole new adaptor and needs to drop all info about the old one.
Even better would be to call one of the more specific notify functions on the adapter that tell it what elements changed, but the general one is good enough until you see perf issues.
Related
I have a nested recycler view that contains parent and child adapters. I am using Room DB for showing data on the recycler view.
When I, add or delete data from a parent or child list item or parent list item, it goes to the first position.
This is how I, collect data from the view model
This is how I, collect data from Room DB and emit for activity
These are some edit delete operations executing in the activity
I just want when I, execute any operation the position remains the same not scroll for the first position. There is also a solution called the smooth Scroll To Position method but I want a solution without using this function.
In your collect lambda, you are setting the recyclerView's adapter every time a new flow is collected, which is making your recyclerView go on the top.
You should move binding!!.parentRecyclerView.adapter = adapter to either onCreate if using inside an activity or onViewCreated if fragment.
You can also do a null check and set only if the recycler views adapter is null. This should be avoided as it is more idiomatic to set it when the view gets created.
I have a recyclerView and list of items. Items are observed in viewModel, adapter gets a changed list whenever list in viewModel changes.
However, I have a problem when updating certain item views in existing list item - these changes happen, but to see them I have to scroll up or down a bit. In view holder I have all necessary if/else cases what to update according to item values. Is there a way to update item view instantly, without having to scroll?
You can call adapter.notifyDataSetChanged() function to force the adapter to redraw all items again.
you should use adapter.notifyItemChanged(int indexOfChangedItem) or adapter.notifyDataSetChanged() after you changing any item of the list.
the first one will update 'all' item viewes but the second one will update only the view that you passed it's index.
I have a ListView which I populate using a custom CursorAdapter.
Now I want to manually update just one specific item in the ListView. I have the content URI of that item. Is it possible to use just this info to get the position of the item in the listView?
If I have the position I can do something like
View v = mListView.getChildAt(itemPosition - mListView.getFirstVisiblePosition());
to update the view. But how can I get itemPosition?
I know that I get the position in the onItemClickListener, but I need to update the view without it being clicked.
Any help guys?
ListView does not support updating a single position.
You must update the adapter with the new data (even if you change a single position) and the, invoke mAdapter.notifyDataSetChanged()
If you get the View by its position (via listView.getChildAt()) will work. However, if you scroll up and down the list, that view will display the old data again because the adapter is not aware of the change (and it is the adapter which update the view contect view getView()).
When you invoke notifyDataSetChanged(), you are telling to the adapter that your data set has new info and the ListView/Adapter will re-draw the visible items (it won't re-draw whole list at once.. only the visible items).
You may want to consider to change to RecyclerView in the future. The BaseAdapter used in a RecyclerView support actions such as add/remove/update a single position.
I have a RecyclerView and one item row needs to be updated like every second (SeekBar). So I call NotifyDataSetChanged once I update the data in the list. UI gets updated but the issue is that the RecyclerView scrolls so that this particular item is either at top or bottom of the screen.
I don't want RecyclerView to scroll.
// Update Data
mData.set(mData.indexOf(cardData), cardData);
// RefreshView
refreshView() {
runOnUiThread(new Runnable(){
notifyDataSetChanged();
}
);
You can update one item using notifyItemChanged(position); and u wont update all data in adapter, you will update only certain item
It's better to use the other notify methods from the RecyclerView.
For your usecase only swap out one item in your Adapter instead of all items and use notifyItemChanged(position).
This will be faster, the View won't scroll and if you ever will add an animation this will only work if you don't use notifyDataSetChanged
I got it working. I was having a card view above the recycler view.I just removed it. Now the whole screen is a recyclerView and I cannot see any auto scrolls.
I have a list view fed by BaseAdapter.
When something changes in data, I call BaseAdapter.notifyDataSetChanged. All works fine.
Now I wonder, if I change some tiny detail in some list item, is there some optimized way to update view of single item if it's displayed on screen?
I suppose that notifyDataSetChanged blindly rebuilds views of all visible items in list, which is not optimal if trivial change in item happens.
No, I guess it's not possible unless you implement your own ListView class extension.
Here there is the source code for setAdapter().
You will see, the ListView only registers itself as observer using mAdapter.registerDataSetObserver(mDataSetObserver);
And a DataSetObserver provides no means to notify about a change at a certain position.
However it might not be necessary to notify about updates of certain items, because as far as I know, a ListView only renders and updates the items currently seen on the screen so, no optimization should be necessary here.
Yes, there is way. Assuming I can identify list item, for example by assigning View.setTag to it to some value, I can iterate list items and rebind only one list item if desired, or even update only some sub-view of the item.
It's simple and relatively cheap (linear search):
for(int i = list.getChildCount(); --i>=0; ){
View v = list.getChildAt(i);
Object id = v.getTag();
if(id==myId){
updateListItem(id, v);
break;
}
}
where myId is some ID of item I want to update, and updateListItem makes desired changes on the list item. Proved, and working fine and very efficiently.