I'm trying to use in my Android Application the notifyDataSetChanged() method for an ArrayAdapter but it doesn't work for me.
I found as answer here, that notifyDataSetChanged() should run in the main thread, but there was no example for that.
Could anybody send an example or at least a link?!
For an ArrayAdapter, notifyDataSetChanged only works if you use the add(), insert(), remove(), and clear() on the Adapter.
When an ArrayAdapter is constructed, it holds the reference for the List that was passed in. If you were to pass in a List that was a member of an Activity, and change that Activity member later, the ArrayAdapter is still holding a reference to the original List. The Adapter does not know you changed the List in the Activity.
Your choices are:
Use the functions of the ArrayAdapter to modify the underlying List (add(), insert(), remove(), clear(), etc.)
Re-create the ArrayAdapter with the new List data. (Uses a lot of resources and garbage collection.)
Create your own class derived from BaseAdapter and ListAdapter that allows changing of the underlying List data structure.
Use the notifyDataSetChanged() every time the list is updated. To call it on the UI-Thread, use the runOnUiThread() of Activity.
Then, notifyDataSetChanged() will work.
You can use the runOnUiThread() method as follows. If you're not using a ListActivity, just adapt the code to get a reference to your ArrayAdapter.
final ArrayAdapter adapter = ((ArrayAdapter)getListAdapter());
runOnUiThread(new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
});
I recently wrote on this topic, though this post it old, I thought it will be helpful to someone who wants to know how to implement BaseAdapter.notifyDataSetChanged() step by step and in a correct way.
Please follow How to correctly implement BaseAdapter.notifyDataSetChanged() in Android or the newer blog BaseAdapter.notifyDataSetChanged().
I had the same problem and I prefer not to replace the entire ArrayAdapter with a new instance continuously. Thus I have the AdapterHelper do the heavy lifting somewhere else.
Add this where you would normally (try to) call notify
new AdapterHelper().update((ArrayAdapter)adapter, new ArrayList<Object>(yourArrayList));
adapter.notifyDataSetChanged();
AdapterHelper class
public class AdapterHelper {
#SuppressWarnings({ "rawtypes", "unchecked" })
public void update(ArrayAdapter arrayAdapter, ArrayList<Object> listOfObject){
arrayAdapter.clear();
for (Object object : listOfObject){
arrayAdapter.add(object);
}
}
}
I know this is a late response but I was facing a similar issue and I managed to solve it by using notifyDataSetChanged() in the right place.
So my situation was as follows.
I had to update a listview in an action bar tab (fragment) with contents returned from a completely different activity. Initially however, the listview would not reflect any changes. However, when I clicked another tab and then returned to the desired tab,the listview would be updated with the correct content from the other activity. So to solve this I used notifyDataSetChanged() of the action bar adapter in the code of the activity which had to return the data.
This is the code snippet which I used in the activity.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId())
{
case R.id.action_new_forward:
FragmentTab2.mListAdapter.notifyDataSetChanged();//this updates the adapter in my action bar tab
Intent ina = new Intent(getApplicationContext(), MainActivity.class);
ina.putExtra("stra", values1);
startActivity(ina);// This is the code to start the parent activity of my action bar tab(fragment).
}
}
This activity would return some data to FragmentTab2 and it would directly update my listview in FragmentTab2.
Hope someone finds this useful!
Related
I'm trying to use in my Android Application the notifyDataSetChanged() method for an ArrayAdapter but it doesn't work for me.
I found as answer here, that notifyDataSetChanged() should run in the main thread, but there was no example for that.
Could anybody send an example or at least a link?!
For an ArrayAdapter, notifyDataSetChanged only works if you use the add(), insert(), remove(), and clear() on the Adapter.
When an ArrayAdapter is constructed, it holds the reference for the List that was passed in. If you were to pass in a List that was a member of an Activity, and change that Activity member later, the ArrayAdapter is still holding a reference to the original List. The Adapter does not know you changed the List in the Activity.
Your choices are:
Use the functions of the ArrayAdapter to modify the underlying List (add(), insert(), remove(), clear(), etc.)
Re-create the ArrayAdapter with the new List data. (Uses a lot of resources and garbage collection.)
Create your own class derived from BaseAdapter and ListAdapter that allows changing of the underlying List data structure.
Use the notifyDataSetChanged() every time the list is updated. To call it on the UI-Thread, use the runOnUiThread() of Activity.
Then, notifyDataSetChanged() will work.
You can use the runOnUiThread() method as follows. If you're not using a ListActivity, just adapt the code to get a reference to your ArrayAdapter.
final ArrayAdapter adapter = ((ArrayAdapter)getListAdapter());
runOnUiThread(new Runnable() {
public void run() {
adapter.notifyDataSetChanged();
}
});
I recently wrote on this topic, though this post it old, I thought it will be helpful to someone who wants to know how to implement BaseAdapter.notifyDataSetChanged() step by step and in a correct way.
Please follow How to correctly implement BaseAdapter.notifyDataSetChanged() in Android or the newer blog BaseAdapter.notifyDataSetChanged().
I had the same problem and I prefer not to replace the entire ArrayAdapter with a new instance continuously. Thus I have the AdapterHelper do the heavy lifting somewhere else.
Add this where you would normally (try to) call notify
new AdapterHelper().update((ArrayAdapter)adapter, new ArrayList<Object>(yourArrayList));
adapter.notifyDataSetChanged();
AdapterHelper class
public class AdapterHelper {
#SuppressWarnings({ "rawtypes", "unchecked" })
public void update(ArrayAdapter arrayAdapter, ArrayList<Object> listOfObject){
arrayAdapter.clear();
for (Object object : listOfObject){
arrayAdapter.add(object);
}
}
}
I know this is a late response but I was facing a similar issue and I managed to solve it by using notifyDataSetChanged() in the right place.
So my situation was as follows.
I had to update a listview in an action bar tab (fragment) with contents returned from a completely different activity. Initially however, the listview would not reflect any changes. However, when I clicked another tab and then returned to the desired tab,the listview would be updated with the correct content from the other activity. So to solve this I used notifyDataSetChanged() of the action bar adapter in the code of the activity which had to return the data.
This is the code snippet which I used in the activity.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId())
{
case R.id.action_new_forward:
FragmentTab2.mListAdapter.notifyDataSetChanged();//this updates the adapter in my action bar tab
Intent ina = new Intent(getApplicationContext(), MainActivity.class);
ina.putExtra("stra", values1);
startActivity(ina);// This is the code to start the parent activity of my action bar tab(fragment).
}
}
This activity would return some data to FragmentTab2 and it would directly update my listview in FragmentTab2.
Hope someone finds this useful!
I have some questions about ListView. The Post that I've searched doesn't satisfy me.
If I have five list items and call notifyDataSetChanged() method in
customAdapter, How many times does getView method called?
I have a checkbox on each list and it must be shown only when the delete button is clicked. The Delete button is created on the Activity Class, and the checkbox is created in the Adapter Class (I mean findViewById). Then how can I handle this?
Currently my code changes flag value on Activity Class and call
notifyDataSetChanged() method on Adapter Class.
How can I handle UI without call notifyDataSetChanged() method?
(I've implemented in this way...)
Sorry about not posting my code.
Get view calls every time when item appears at the screen, so in your case it is 5 times.
You can do something like that:
2.1 Create a public method in your adapter, for example:
public void setIsDeleteModeEnabled(boolean isEnabled) {
//Logic here
}
2.2 In your Activity, when Button is clicked call adapter.setDeleteModeEnabled(true);
3 You should call notifyDataSetChanged() only when dataset is changed. For handling UI events you should:
In list item: you should set onClickListeners in getView();
In Activity : onCreate() method in adapter and call it in Activity's onClicks
I am trying to display a list fragment in the middle of my activity. The list fragment adapter is a custom adapter (extended from BaseAdapter) with the typical ViewHolder pattern. It is implemented correctly.
I have the adapter set up with greenrobot Eventbus to receive a new List object from an asynctask which does the query in the background (as not to slow down the UI Main Thread).
The problem is the list fragment doesn't have the results of the database query initially so it defaults to empty (and displays the textview in my xml for the main activity which has the id 'empty').
In the end, my adapter, and listviewfragment don't get instaniated at all because it defaults to empty.
Is there a better method to doing this?
How can I get my listview fragment to wait for the data recieved from the asyncTask?
I am going to just do a fragment with a listview in it, instead of a listview fragment, and I'll see if that will help.
As I understood correctly, you did everything okay so far. What you have to do is to add an "update" method to your adapter, and call this whenever your asynctask finished it's job and got the results for you.
This update method should look something like
public void updateAdapterData(List<String> newList) {
mItems.clear(); // say mItems is the global list you have in the adpater
mItems.addAll(newList);
notifyDataSetChanged(); // This will cause the adpater to re-draw it's rows, so now data should be visible in your list
}
And in your fragment you do somehting like:
adpater.updateAdapterData(newList);
Does this help?
If I have a ListView with a CustomAdapter and let's say I have this refresh() method that refreshes the list with new results, should I:
Call new CustomAdapter(...) upon initialization, and every time I call refresh(), I use adapter.clear() and adapter.add(...)
Call new CustomAdapter(...) every time I call refresh()
Basically, I'm asking, is it better to recreate an adapter everytime I load new results or is it better to clear the results in existing adapter and add the entire list to it?
I think if you're going to use adapters as they were intended, then you'll update the adapter's data and call notifyDataSetChanged() on it.
If you look at the API for something like ArrayAdapter, it has numerous methods like clear(), add(), addAll(), notifyDataSetChanged() and so forth that are there to guide you towards a certain use of the API.
By using these methods, not only does it make your code compliant with its intended usage, it also makes it easier to understand and familiar to others that are trying to understand your code.
So basically, I would only recreate the adapter as a last resort.
It is definitely better to call notifyDataSetChanged() on the original adapter than setting a new one.
The reason is performance: ListView uses view recycling to avoid creating new item views as you scroll. When you set a new adapter, these recycled views are discarded, which means they must be recreated from scratch for the next layout pass. Take a look at the code of ListView.setAdapter():
#Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
...
This is completely logical behavior, since the ListView supposes that the views the new adapter will use are incompatible with the ones returned by the previous adapter (in any case, it cannot assume that they will be compatible). So they're thrown away.
Therefore, if you set a new adapter each time, you're incurring an unnecessary performance cost (recreating all the current views).
Also, if you wrote a custom adapter, you don't necessarily have to call add() individually (as with, say, ArrayAdapter). You can just replace the internal data collection with the new one and call notifyDataSetChanged() afterwards.
I am having a problem where when I call the adapter.notifyDataSetChange() to refresh the listActifity from the onResume() function, it doesn't seem to be working from any other functions from that activity afterwards.
I want the list(view) to refresh when the user clicks the back button(while on another screen) and returns to the window with the list.
One of the things I noticed is that the notifyDataSetChange() works(from other functions) when I change one of the objects from the array list but not when I want to add or delete an object from the ArrayList. This has been working so far for me, but I would prefer not to have to requery the list every time.
#Override
protected void onResume() {
lightWeightDAO.open(); //db connection
adapter.clear();
buckets = lightWeightDAO.getExerciseBucketsByWorkoutId(workout.getId());
adapter.addAll(buckets);
adapter.notifyDataSetChanged();
super.onResume();
}
When I remove the notifyDataSetChange() from the onResume(), everything seems to work(just calling a simple notifyDataSetChange() after changing the arraylist).
Any idea why this is not working?
By using:
buckets = lightWeightDAO.getExerciseBucketsByWorkoutId(workout.getId());
adapter.addAll(buckets);
You have only added the contents of this new buckets to the adapter, you didn't bind the adapter to buckets. So this:
buckets.add(string);
adapter.notifyDataSetChanged();
has no affect on the data inside the adapter. Also like I mentioned above in the comments, you can add to the adapter directly and it will call notifyDataSetChanged() for you. So simply replace everywhere you use the two lines above with:
adapter.add(string);