179

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?!

Community
  • 1
  • 1
Tima
  • 12,765
  • 23
  • 82
  • 125
  • http://stackoverflow.com/questions/14503006/android-listview-not-refreshing-after-notifydatasetchanged – ranjan Jan 28 '14 at 06:49
  • you can check this [blog](https://thedeveloperworldisyours.com/android/notifydatasetchanged/) and this [example in github](https://github.com/thedeveloperworldisyours/FullRecyclerView) and [this as well](https://github.com/CabezasGonzalezJavier/NotifyDataSetChanged) – Cabezas Oct 29 '18 at 17:46

6 Answers6

339

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:

  1. Use the functions of the ArrayAdapter to modify the underlying List (add(), insert(), remove(), clear(), etc.)
  2. Re-create the ArrayAdapter with the new List data. (Uses a lot of resources and garbage collection.)
  3. Create your own class derived from BaseAdapter and ListAdapter that allows changing of the underlying List data structure.
  4. 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.
Sufian
  • 6,405
  • 16
  • 66
  • 120
jnosek
  • 4,223
  • 2
  • 19
  • 20
  • 14
    be careful, too, of assigning 'new' objects to your data. use clear() instead, repopulate/make changes to data, then call notifyDataSetChanged() – moonlightcheese Apr 07 '11 at 12:32
  • But what if we call `notifyDataSetChanged()` in such manner: `((BaseAdapter) arrayAdapter).notifyDataSetChanged();`? – teoREtik Jan 26 '12 at 08:11
  • 2
    I use BaseExpandableListAdapter, it doesn't have add() or remove() functions so I store my Map as a member variable. I update Map and call notifyDatasetChanged() but nothing happens. When I use the choice #4, it works. Why??? – emeraldhieu Dec 25 '12 at 07:49
  • I'm using ArrayAdapter for custom GridView, I'm adding images as I get them from urls by calling adapter.add(dataReceived). This works fine adds data but why it's refreshing & going to top. I want to show items as they will get add without refreshing list. (What want to do is working with android's GridView using notifyDatasetChanged()) How can I make It work in this customGridView(StaggeredGridView). – MobileEvangelist May 15 '13 at 09:47
  • 1
    I tried creating my own BaseAdapter to add sorting methods to the list, but for some reason it just wouldn't work. Not that my app is slow even if I recreate the entire adapter with a sorted arraylist, but it still irks me. How exactly would it create a lot of garbage though? I assume the actual array of costly data is kept as a reference in the activity calling the adapter, meaning only the adapter will be collected. – G_V Nov 10 '14 at 09:39
  • i tried notifyDataSetChanged() inside onPostExecute of AsyncTask, but it didn't work. i then used runOnUiThread() inside onPostExecute and this worked. Can anyone tell me why. i though onPostExecute runs on UI thread anyway. – turtleboy Dec 17 '14 at 12:06
  • if useful, I found a perfect example (super simple) here: https://thedeveloperworldisyours.com/android/notifydatasetchanged/ – Javier C. H. Oct 09 '18 at 01:23
  • 1
    Remember that when `notifyDataSetChanged()` is called, the array declared `in the adapter` will be checked. So you should create an `public` method in the adapter like `updateArrayList` which would modify the declared array. Remember to use `ArrayList` methods like`add()`, `insert()`, `remove()`, or `clear()` to update the items. Also, remember to update the array size which is used in the `getItemCount()` in the RecycylerView's adapter. The parameter is used to determine the RecyclerView's row number. – Alston Jun 07 '19 at 14:46
36

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();
    }
});
Dev-iL
  • 23,742
  • 7
  • 57
  • 99
Brian
  • 16,196
  • 3
  • 27
  • 28
  • 1
    I tried to add the code fragment of you in my code (you can find it here http://stackoverflow.com/questions/3667442/how-to-refresh-adapter) in onCreate-method, but I still don't have any success :( Maybe it was wrong place to adding it?! – Tima Sep 08 '10 at 16:37
  • 1
    Your question just asked how you could call the method and have it run in the main UI thread. This answers that question. In your particular case (http://stackoverflow.com/questions/3670500/notifydatasetchanged-doesnt-work/3670861#3670861) AsyncTask and its onPostExecute() method seem to be what you should consider. – Brian Sep 09 '10 at 04:03
12

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().

Arif Nadeem
  • 8,524
  • 7
  • 47
  • 78
  • Hi i tried first link example,but instead of `mItem.add()`, i have done just editing one element means like `mItem.get(position).setImage(encodedImage)` may be thats why it is giving error NullPointer exeption.So does notifyDataSetChange work on just editing it,bcz for Array adapter it is mentioned above it work only for add(),clear(),remove() etc – Shreekant N Sep 01 '15 at 10:42
  • notifyDataSetChanged will work for editing or modifying data set, your null pointer is because of something else, check the logs. – Arif Nadeem Sep 01 '15 at 18:41
7

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);
        }
    }
}
casperOne
  • 73,706
  • 19
  • 184
  • 253
Kevin Parker
  • 16,975
  • 20
  • 76
  • 105
  • I have a couple other ArrayAdapters in my code and they have worked without issue. Tonight, I decided to turn a SimpleCursorAdapter into an ArrayAdapter, and it WOULD NOT WORK. After struggling with it for a few hours and trying to find a reason why it would not work, I found your AdapterHelper class, and NOW IT WORKS! Thanks! – proudgeekdad Jul 08 '12 at 04:45
  • 1
    This can easily be done in a function... WHY would you instantiate a new class for it? – techi.services Aug 09 '12 at 06:44
  • 2
    In Java functions are called methods. What would you propose, have this highly re-usable method in the same class as the Array Adapter perhaps? Or the Fragment / Activity containing the list view? So yes, its in a class where it can be reused. If you want to make it static by all means go ahead. – Kevin Parker Aug 09 '12 at 16:22
  • 1
    Nice idea. Another one would be to extend ArrayAdapter, named ArrayAdapterCompat and override the addAll(..) method, since this one is only available since API 11. In there, check the API level and use `super.addAll(..)` for API > 11 and super.add(..) in combination with iteration like yours: `if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { super.addAll(items); } else { for (Object o : collection) { super.add(o); } }`. Now just extend from your new adapter class. – Konsumierer Oct 26 '12 at 08:49
  • @hey Kevin I'm unable to resolve using this method can u eloborate please – Praneeth Jun 30 '15 at 09:46
3

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!

Dev-iL
  • 23,742
  • 7
  • 57
  • 99
mutp
  • 2,301
  • 1
  • 17
  • 13
1

Well There is multiple notifiers in Recyclerview that will be called at different events.

1. notifyDataSetChanged()

  • If you change multiple data at a time then you need to apply notifyDataSetChanged().

2. notifyItemInserted ( position : Int )

  • If you Insert data oneByOne in your arrayList then you don't need to do notifyDataSetChanged() because whenever you called notifyDataSetChanged() it will call onBindViewHolder() as many times as your arrayList size. And that's not good practice in my scenario. so that's why when you need to insert item's one by one then always need to use yourAdapter.notifyItemInserted(position : Int) and gives parameter that you inserted a data.

  • Mostly you need to pass as a position in notifyItemInserted(list.size) because you always insert data at the end of the arrayList.

3. notifyItemRemoved ( position : Int )

  • when you remove item from a particular position in a list then you need to use notifyItemRemoved ( position : Int ) method to notify the adapter that update your list and removed this item at this position.

4. notifyItemChanged ( position : Int )

  • when you update your list at a particular position then you need to notify the adapter with notifyItemChanged() with a parameter of a position that you were updated.