I searched for hours but still have no explanation (even not in official docu) what is the right way to use a RecyclerView.Adapters' notify-methods. Already read a lot of similar question on SO, but no could solve my simple problem. I try to put down a short, simplified example.
class MyAdapterClass extends RecyclerView.Adapter<MyAdapterClass.MyViewHolderClass> {
...
List myItemList = new ArrayList<MyItemType>();
...
}
RecyclerView myRecView = (RecyclerView) findViewById(R.id.myRecView);
myRecView.setAdapter(new MyAdapterClass(...)));
Even when inserting the first item, the view is not refreshed.
myAdapter.myItemList.add(newItem);
myAdapter.notifyItemInserted(myAdapter.myItemList.size() - 1);
If I then tightly touch (try to scroll) the 1-item-listview, the item appears. So it seams to be a refreshing issue. But why? I have an emtpy list, then I insert one item, then I notify the adapter about the insertion. Whats wrong with my expectation?
By the way, even if I additionally call:
myAdapter.notifyItemChanged(myAdapter.myItemList.size() - 1);
it gets not automatically refreshed.
EDIT: And of course, I dont want to use notifyDataSetChanged() :-) only insert, update, remove on an existing list.
Try to add this code inside your adapter class :
#Override
public int getItemCount() {
return myItemList.size();
}
i hope you define in adpter getItemCount() in list size. then used blow code for notify adapter.
myadapter.notifyItemRangeChanged(0, userDataArrayList.size());
Related
I want to update my Recyclerview items whenever there is a data change in Firestore.
So my activity have the following code:
taskViewModel.fetchedTaskLiveData.observe(
this, Observer {
if (it != null) {
todoListAdapter.setListData(it)
showRecyclerView()
}
Inside adapter setListData method:
fun setListData(data: MutableList<Todo>) {
//this.todoList.clear()
this.todoList.addAll(data)
notifyDataSetChanged()
}
In this situation, whenever a changed list is fetched, Recyclerview is duplicating and adding the changed
list below the old list.
And if "this.todoList.clear()" is uncommented, list is getting cleared and no data is showing on data change.
I tried all possible solutions, but I think somewhere am missing a part. stuck since a long time.
Thanks a lot for all kind of suggestion.
So I was stuck with this and found out after 12 hours a tiny change.
I corrected it by changing for with forEach and that changed the game.
Also I am clearing list items before adding the items.
todoList.clear()
I have a RecyclerView with its RecyclerView.Adapter and view holder. I am trying to delete an item from list, code as follows inside onClick() on delete button in the ViewHolder
int position = getAdapterPosition();
if(position > -1)
{
Place place = placeList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, getItemCount());
}
Despite removing the view and doing the animation (list also gets affected), the old view (or lower one) still exist or drawn again.
For example, if the list starts with size = 5, then i try to remove index 4, he remove 4, then still draw 5 views.
EDIT
If i remove notifyItemRangeChanged() then it does that bug only if i do the following
1- click on delete
2- click button very quickly that takes me to new view
3- going back to the list where i can delete
4- start deleting, and bug happens. 1 item still remain even though the List size = 0 (getItemCount is called with 0).
If i only call NotifyDataSetChanged(), then it removes item, but view just stays there !!
Any help or suggestion is appreciated.
Thanks.
EDIT complete class LINK
Try this:
placeList.remove(position);
notifyItemRemoved(position);
use below code it will solve your problem.
holder.deleteImg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(list.size()!=0){
list.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position,list.size());
}
}
});
I've had the same problem, notifyItemRangeChanged() call didn't help while notifyDataSetChanged() did (though stopped the animation). But I am using the ItemTouchHelper on the RecyclerView (to allow for moving items around), and it became obvious that this class was causing the trouble.
The only difference in my case is that to reproduce this overlap-after-delete bug, user has to long press on an item while deleting it.
After I modified the overriden isLongPressDragEnabled() method of ItemTouchHelper.Callback to return false instead of true, the issue was solved.
lastImages.remove(position); (lastImages equals your array list)
newContentAdapter.notifyDataSetChanged();
it is works. You have to remove it in your array not item. then notify adapter. Thats all
for me notifyItemRemoved and notifyDataSetChanged doesnt work. I tried everything , only solution that worked for me is calling or reloading recycler view inside onSwiped method!
you don't have to create new reference of place list.that need to declared as array list. you can't add or remove a object from list. you can do that only with arraylist.
change this lines
private List<Place> placeList;
Place place = placeList.remove(position);
to
private ArrayList<Place> placeList;
// other codes
placeList.remove(position);
// print placeList to confirm
notifyItemRemoved(position);
I had this issue
when I'm using notifyDataSetChanged() it works fine but I wanted the animation so I used notifyItemRemoved(position) for animation then I used notifyDataSetChanged() but I delayed the interval between those functions
I made extension for it you can use it on any RecylcerView
fun RecyclerView.removeItem(position: Int){
adapter?.notifyItemRemoved(position)
handler.postDelayed({
adapter?.notifyDataSetChanged()
},300)
}
You need to update you adapter;
Create method in Adapter class where you will be put your data.
For example : setData(List<Place> data);
When last item in list you need to write: adapter.setData(null);
I had the same problem. Just set list = null. It's all.
I have an ArrayAdapter linked to a ListView.
mListView.setAdapter(mArrayAdapter);
Whenever I reset the ArrayList data to the ArrayAdapter:
mArrayAdapter.clear();
mArrayAdapter.addAll(mArrayList);
mArrayAdapter.notifyDataSetChanged()
the ListView gets correctly updated
however, if just after the above three lines, I call my custom method mListView.hasScrollbar() to detect whether the listview has a scrollbar or not, I get a null lastVisibleItem:
public boolean hasScrollbar() {
View lastVisibleItem = (View) getChildAt(getChildCount() - 1);
if (lastVisibleItem.getBottom()>=getHeight()) {
return true;
}
return false;
}
does it mean that the listview is still refreshing?
My main question is:
how can I test if the listview has the scrollbar after resetting the adapter with new data?
thank you for any help!
Using getLastVisiblePosition / getFirstVisiblePosition is a valid method of detecting wether you have scrolling or not within the list view (aslong as you compare it to getCount() and do your math ofc).
The problem you have as you already guess is that you are attempting to check out of sync.
In order to sync your query when the adapter already filled your List Data and updated changes, you need to issue a post request to the list, which will stack that petition to the message queue of the adapter.
yourAdapter.notifyDataSetChanged();
yourAdapter.getListView().post(new Runnable() {
#Override public void run() {
//your code here
}
});
Make sure to call that after notifySetDataChanged() of course. Because you want the list to update before the check.
I think your question equals to "how to tell if list view contains items need to displayed on more than one screen"?
So my suggestion is to use listView.getFirstVisiblePosition() and getLastVisiblePosition() to tell it.
I have dug deep down into SO but, although I have found other people asking similar questions to mine, I have not yet find a question that addresses the same issues I have. I have not found a satisfying answer either.
I have a ListView. When I call from the adapter, .notifyDataSetChanged, the ListView is updated, but I can see the update only once onResume() is called. In other words, I do not see it instantly, only after I leave the activity and comeback.
What can I do to see the update instantly? I have tried the .notifyDataSetChanged method, I have tried resetting the adapter... nothing worked.
According to your comment, you dont update the array IN the adapter, but an array held by the activity you passed to the adapter once. Thats why the adapter isnt updating properly. You are changing the array outside of your adapter-class, which might not be the same array-object your adapter is using. At onResume(), your adapter is recreated with the new array and showing the new content.
A solution would be using the following custom Adapter class:
class MyAdapter extends BaseAdapter {
private Array[] myArray;
public MyAdapter(Array[] myArray) {
this.myArray = myArray;
}
public updateContent(Array[] myNewArray) {
this.myArray = myNewArray;
this.notifyDataSetChanged();
}
// your getItem, getView, and so on methods
}
Then from your activity, simple call myArray.updateContent() with your new Array and it will update immediatly.
Its never good to hold and manipulate an object used from one class (the adapter) within another one (the activity). Try to move all code for manipulating the array into the adapter and use methods to add/remove items. This will make it a lot easier finding this kind of errors!
EDIT 2:
I did solve my problem, but i don't know how:S I was moving my code snippets a bit around, a suddenly it worked. Must have done something in the wrong order, but its weird, checked it many times. Thanks for you help, and sorry I can't post an answer ;)
Hi.
I have a list view which I'm trying to refresh to update it self when i add an element to
the underlying array list.
Here is the code snippet:
private void addEvent() {
arrlEvents.add( event );
adptEvents.notifyDataSetChanged();
updateSaveFile();
filterList();
}
The arrlEvents is the underlying arraylist with the events, and im adding one event, trying to update the list view with notifyDataSetChanged(), but it doesnt work. Can anyone help?
Thanks for your time:)
EDIT:
Here is the source code for the adapter:
private ArrayAdapter<Event> adptEvents;
adptEvents = new ArrayAdapter<Event>( EventCalendar.this, R.layout.list_items, arrlEvents );
I have seen that sometimes it just randomly doesnt notify the adapter.
Try using adptEvents as protected or public on a global scope.
I have found that when that doesnt work. You can just re set the adapter again, just substitute the notifyDataSetChanged() for:
adptEvents = new ArrayAdapter<Event>( EventCalendar.this, R.layout.list_items, arrlEvents );
Edit:
Heres a code snipper from an App I wrote that works.
Class definition:
public class ClassName extends ListActivity implements AdapterView.OnItemSelectedListener {
Global Variable:
CustomAdapter adapter;
in OnCreate():
adapter = new CustomAdapter(this,R.layout.layout_name,dataSet);
setListAdapter(adapter);
Whenever I need to notify
adapter.notifyDataSetChanged();
There is no persistent link between arrlEvents and the adptEvents.... the latter simply initialises itself with the elements from the former. adptEvents has no way to know when arrlEvents changes.
To add new items you should call adptEvents.add(event) and not bother calling notifyDataSetChanged() explicitly, since ArrayAdapter.add() does that for you automatically.