456

How to refresh an Android ListView after adding/deleting dynamic data?

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
UMAR-MOBITSOLUTIONS
  • 77,236
  • 95
  • 209
  • 278
  • 3
    If other solutions don't work, try refreshDrawableState. Props to http://stackoverflow.com/questions/5186359/donenotifydatasetchanged-does-not-update-listactivity-automatically – Edwin Evans May 05 '12 at 22:33
  • May be help you, http://stackoverflow.com/a/17333384/596555 – boiledwater Jun 27 '13 at 02:03
  • An example here https://www.tutorialkart.com/kotlin-android/android-refresh-listview-example/ may help you. – arjun Apr 17 '18 at 12:35

26 Answers26

551

Call notifyDataSetChanged() on your Adapter object once you've modified the data in that adapter.

Some additional specifics on how/when to call notifyDataSetChanged() can be viewed in this Google I/O video.

Kaushik
  • 6,150
  • 5
  • 39
  • 54
Christopher Orr
  • 110,418
  • 27
  • 198
  • 193
  • 25
    You should run it on the UI thread. Create an handler within the UI thread and then post Runable to it – Kirill Kulakov Feb 22 '13 at 15:58
  • 11
    Once again: notifyDataSetChanged() does not work at least not for use practices which are recomended (read not deprecated). If use listview, cursor adapter and content provider you might try something along the lines: gettLoaderManager().restartLoader(). See: http://stackoverflow.com/a/19657500/1087411 I would like to see at least some documentation on notifyDataSetChanged(). To much in android is left to black box testing. – Anderson Apr 13 '14 at 11:44
  • If notifyDataSetChanged does not work, you are the one who is doing it wrong – zdarsky.peter May 08 '14 at 22:10
  • 5
    notifyDataSetChanged does not always work. I'm not sure why this is in contention. Sometimes you have to call listView.setAdapter(adapter) to clear out the old views. See also: http://stackoverflow.com/a/16261588/153275 –  Jul 08 '14 at 16:48
  • This video could be helpful to someone. It helped me :) https://www.youtube.com/watch?v=hJQmvRHF5xg – Gabriel Muñumel Dec 16 '14 at 22:19
  • @Christopher Orr its work but it return many copies of last list with new list – Sasha Jan 05 '15 at 03:57
  • 2
    I was never able to get notifyDataSetChanged working. I could clearly see that the collection I feed to the adapter has changed (elements were removed) but notifyDataSetChanged has never done anything. Not sure if this method is just broken? – byemute Oct 22 '15 at 08:42
  • in my product list data with isinwishlist flag if user clicked on product from list goes to detail view with that model data in extras if user do any changes on detail page those updated status is not reflected on list please help me – Harsha Nov 07 '16 at 12:01
  • I have been looking into a solution for my firebase wait date fetch for ours, I only thought about refreshing the list at the end, this worked like charm, THANKS!!! – masood elsad Aug 14 '17 at 22:22
  • As mentioned above, this method only works if you've modified the data structure. If the contents within the data structure change, `notifyDataSetChanged()` does not work. `listView.setAdapter(adapter)` does work to clear the cached views. – Bryan W. Wagner Sep 18 '19 at 14:54
  • I have added a similar [question](https://stackoverflow.com/q/67705242/6854117) can you please check it out? – Moeez May 26 '21 at 12:59
213

Also you can use this:

myListView.invalidateViews();
nbro
  • 15,395
  • 32
  • 113
  • 196
Bob
  • 22,810
  • 38
  • 143
  • 225
  • 25
    This is the correct answer if one only needs to REDRAW the view. For example, after a user login occurs that needs to expose more info or options within each view of the listView. That's what I needed to do, so gave an up-vote. If the underlying data changes, it's probably a better idea to use notifyDataSetChanged(). – SBerg413 Jun 06 '13 at 14:05
  • 1
    Actually `invalidateViews()` in the source code sets `mDataChanged = true;` so I'm not sure if this results in better performance compared to `notifyDataSetChanged()` – vovahost Feb 17 '15 at 15:06
  • you can take a type of list which is "observable list" ,no need to notifydataset changed – Priya Mar 05 '18 at 11:15
  • actually this helped me. notifyDataChanged() didnt update the view. – cantona_7 Aug 27 '20 at 13:12
157

Please ignore all the invalidate(), invalidateViews(), requestLayout(), ... answers to this question.

The right thing to do (and luckily also marked as right answer) is to call notifyDataSetChanged() on your Adapter.

Troubleshooting

If calling notifyDataSetChanged() doesn't work all the layout methods won't help either. Believe me the ListView was properly updated. If you fail to find the difference you need to check where the data in your adapter comes from.

If this is just a collection you're keeping in memory check that you actually deleted from or added the item(s) to the collection before calling the notifyDataSetChanged().

If you're working with a database or service backend you'll have to call the method to retrieve the information again (or manipulate the in memory data) before calling the notifyDataSetChanged().

The thing is this notifyDataSetChanged only works if the dataset has changed. So that is the place to look if you don't find changes coming through. Debug if needed.

ArrayAdapter vs BaseAdapter

I did find that working with an adapter that lets you manage the collection, like a BaseAdapter works better. Some adapters like the ArrayAdapter already manage their own collection making it harder to get to the proper collection for updates. It's really just an needless extra layer of difficulty in most cases.

UI Thread

It is true that this has to be called from the UI thread. Other answers have examples on how to achieve this. However this is only required if you're working on this information from outside the UI thread. That is from a service or a non UI thread. In simple cases you'll be updating your data from a button click or another activity/fragment. So still within the UI thread. No need to always pop that runOnUiTrhead in.

Quick Example Project

Can be found at https://github.com/hanscappelle/so-2250770.git. Just clone and open the project in Android Studio (gradle). This project has a MainAcitivity building a ListView with all random data. This list can be refreshed using the action menu.

The adapter implementation I created for this example ModelObject exposes the data collection

public class MyListAdapter extends BaseAdapter {

    /**
     * this is our own collection of data, can be anything we 
     * want it to be as long as we get the abstract methods 
     * implemented using this data and work on this data 
     * (see getter) you should be fine
     */
    private List<ModelObject> mData;

    /**
     * our ctor for this adapter, we'll accept all the things 
     * we need here
     *
     * @param mData
     */
    public MyListAdapter(final Context context, final List<ModelObject> mData) {
        this.mData = mData;
        this.mContext = context;
    }

    public List<ModelObject> getData() {
        return mData;
    }

    // implement all abstract methods here
}

Code from the MainActivity

public class MainActivity extends Activity {

    private MyListAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView list = (ListView) findViewById(R.id.list);

        // create some dummy data here
        List<ModelObject> objects = getRandomData();
        // and put it into an adapter for the list
        mAdapter = new MyListAdapter(this, objects);
        list.setAdapter(mAdapter);

        // mAdapter is available in the helper methods below and the 
        // data will be updated based on action menu interactions

        // you could also keep the reference to the android ListView 
        // object instead and use the {@link ListView#getAdapter()} 
        // method instead. However you would have to cast that adapter 
        // to your own instance every time
    }

    /**
     * helper to show what happens when all data is new
     */
    private void reloadAllData(){
        // get new modified random data
        List<ModelObject> objects = getRandomData();
        // update data in our adapter
        mAdapter.getData().clear();
        mAdapter.getData().addAll(objects);
        // fire the event
        mAdapter.notifyDataSetChanged();
    }

    /**
     * helper to show how only changing properties of data 
     * elements also works
     */
    private void scrambleChecked(){
        Random random = new Random();
        // update data in our adapter, iterate all objects and 
        // resetting the checked option
        for( ModelObject mo : mAdapter.getData()) {
            mo.setChecked(random.nextBoolean());
        }
        // fire the event
        mAdapter.notifyDataSetChanged();
    }
}

More Information

Another nice post about the power of listViews is found here: http://www.vogella.com/articles/AndroidListView/article.html

JJD
  • 50,076
  • 60
  • 203
  • 339
hcpl
  • 17,382
  • 7
  • 72
  • 73
  • 16
    you're wrong. notifyDataSetChanged() didn't worked for me, but invalidateViews() did it right. – babay Sep 08 '13 at 09:31
  • 6
    I have the issue where the actual elements in the list do not change, e.g. same amount of elements. But the problem is that the way they are presented needs to change. That means my adapter's code to build the UI needs to run again and then correctly hide some element in the list rows. notifyDataSetChanged() does not work... – Sven Haiges Nov 08 '13 at 09:49
  • @hcpl I have a problem with with `listview` and `notifyDataSetChanged()` works, but with delay. After updating data I'm calling `notifyDataSetChanged()` and after that I need to update my component, which gets from `ListView` number of checked items. In this moment, that number is not updated. I know it is updated few moments later. – Ari Nov 28 '13 at 11:18
  • 9
    This answer really helped me out. I was keeping the array in memory for certain feature reasons. To fix it I now call `adapter.clear()`, and `adapter.addAll(Array)` before calling `notifyDataSetChanged()` – Michael DePhillips Feb 26 '14 at 23:09
  • 2
    @hcpl, how should I call notifyDataSetChanged if I'm in the adapter's OnClickListener for a CheckBox? invalidateViews is getting the job done right now. Why is invalidateViews the wrong method to call? – craned Jun 19 '14 at 02:34
  • @SvenHaiges Even if you only update a property of one of the objects in your dataset the notifyDataSetChanged() method is all it takes to get the view updated matching the new properties value. A good practice is to have a getter for your collection (List of model objects for instance) and use that to get the element, update and fire the notifyDataSetChanged on that same adapter. I'll get some basic example online as soon as possible. – hcpl Oct 06 '14 at 18:13
  • Thanks @MichaelDePhillips you get my point :-) That's exactly how it should be done! – hcpl Oct 06 '14 at 18:14
  • @Ari the notifyDataSetChanged() method only triggers the event and the actual update of GUI will be put on queue. If you have a very slow device or a lot of other things going on this might indeed get some delay. However I never noticed a real delay IRL. Do you have example or specs? – hcpl Oct 06 '14 at 18:16
  • You don't need to call `notifyDataSetChanged()` after calling `clear()` or `add()` methods - because they will do it for you. You can see it in the [ArrayAdapter.java](https://github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/ArrayAdapter.java) source code – Alexander Farber Feb 09 '15 at 15:18
  • The key point for those experiencing this type of issue is: *Make sure the data used by the adapter has changed and notifyDataSetChanged() is called at some point from the UI Main Thread*: - via explicit method call: notifyDataSetChanged() - via implicitly method call: clear()/add()/addAll() for ArrayAdapter. Note: setNotifyChange(true) should be called beforehand if setNotifyChange(false) was called earlier. – David Andreoletti Jun 30 '15 at 05:50
  • 1
    I was never able to get notifyDataSetChanged working. I could clearly see that the collection I feed to the adapter has changed (elements were removed) but notifyDataSetChanged has never done anything. Not sure if this method is just broken? – byemute Oct 22 '15 at 08:42
  • 1
    Sorry, down voted because the invalidateViews() worked for me, and your title strongly suggests to ignore it. Please change the title. – Uygar Y Nov 15 '15 at 20:41
  • `ListAdapter`, which is returned by `ListView#getAdapter()`, does not implement `notifyDataSetChanged()`. As a result, you'd need to either maintain a reference to your actual adapter instance or cast the value returned by `getAdapter()`. `invalidateViews()` works and does not require a cast. – Greg Brown Feb 08 '17 at 16:59
  • please answer this related question: https://stackoverflow.com/q/46690220/6144372 – Hammad Nasir Oct 12 '17 at 01:08
  • notifyDataSetChanged() worked for me. Kind of suspect that a lot of the issues here are no longer relevant to modern android development. – Al Ro Jul 07 '23 at 22:17
42

Call runnable whenever you want:

runOnUiThread(run);

OnCreate(), you set your runnable thread:

run = new Runnable() {
    public void run() {
        //reload content
        arraylist.clear();
        arraylist.addAll(db.readAll());
        adapter.notifyDataSetChanged();
        listview.invalidateViews();
        listview.refreshDrawableState();
    }
};
Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
Marckaraujo
  • 7,422
  • 11
  • 59
  • 97
  • 1
    Working also in my case, where I need to update a listview based on data coming from a TCP connection (from a "nonUI" thread). The only way to have the list redrawn was to clear and re-add all the elements of the ArrayList. Anyway, if you are already in the UI thread you don't need to call the code via the `runOnUiThread()` function. – Andre Jan 21 '15 at 11:22
  • 1
    Thanks! It works for me. For all people who want to run this from a fragment, you should use getActivity().runOnUiThread(new Runnable... to make sure the code is run on UI thread – Dũng Trần Trung May 18 '15 at 18:15
  • I do not see the purpose of `run = new Runnable()` and just gave my function a `public void refreshUIThread()` method that models your `run()` method (which works, too). – T.Woody Aug 06 '18 at 22:52
11

i got some problems with dynamic refresh of my listview.

Call notifyDataSetChanged() on your Adapter.

Some additional specifics on how/when to call notifyDataSetChanged() can be viewed in this Google I/O video.

notifyDataSetChanged() did not work properly in my case[ I called the notifyDataSetChanged from another class]. Just in the case i edited the ListView in the running Activity (Thread). That video thanks to Christopher gave the final hint.

In my second class i used

Runnable run = new Runnable(){
     public void run(){
         contactsActivity.update();
     }
};
contactsActivity.runOnUiThread(run);

to acces the update() from my Activity. This update includes

myAdapter.notifyDataSetChanged();

to tell the Adapter to refresh the view. Worked fine as far as I can say.

whostolemyhat
  • 3,107
  • 4
  • 34
  • 50
Wille
  • 111
  • 1
  • 2
9

If you are using SimpleCursorAdapter try calling requery() on the Cursor object.

freehacker
  • 115
  • 1
  • 3
5

if you are not still satisfied with ListView Refreshment, you can look at this snippet,this is for loading the listView from DB, Actually what you have to do is simply reload the ListView,after you perform any CRUD Operation Its not a best way to code, but it will refresh the ListView as you wish..

It works for Me....if u find better solution,please Share...

.......
......
do your CRUD Operations..
......
.....
DBAdapter.open();
DBAdapter.insert_into_SingleList();
// Bring that DB_results and add it to list as its contents....
                                            ls2.setAdapter(new ArrayAdapter(DynTABSample.this,
    android.R.layout.simple_list_item_1,                        DBAdapter.DB_ListView));
                                            DBAdapter.close();
Nandagopal T
  • 2,037
  • 9
  • 42
  • 54
2

The solutions proposed by people in this post works or not mainly depending on the Android version of your device. For Example to use the AddAll method you have to put android:minSdkVersion="10" in your android device.

To solve this questions for all devices I have created my on own method in my adapter and use inside the add and remove method inherits from ArrayAdapter that update you data without problems.

My Code: Using my own data class RaceResult, you use your own data model.

ResultGpRowAdapter.java

public class ResultGpRowAdapter extends ArrayAdapter<RaceResult> {

    Context context;
    int resource;
    List<RaceResult> data=null;

        public ResultGpRowAdapter(Context context, int resource, List<RaceResult> objects)           {
        super(context, resource, objects);

        this.context = context;
        this.resource = resource;
        this.data = objects;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ........
        }

        //my own method to populate data           
        public void myAddAll(List<RaceResult> items) {

        for (RaceResult item:items){
            super.add(item);
        }
    }

ResultsGp.java

public class ResultsGp extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {

    ...........
    ...........
    ListView list = (ListView)findViewById(R.id.resultsGpList); 

    ResultGpRowAdapter adapter = new ResultGpRowAdapter(this,  R.layout.activity_result_gp_row, new ArrayList<RaceResult>()); //Empty data

   list.setAdapter(adapter);

   .... 
   ....
   ....
   //LOAD a ArrayList<RaceResult> with data

   ArrayList<RaceResult> data = new ArrayList<RaceResult>();
   data.add(new RaceResult(....));
   data.add(new RaceResult(....));
   .......

   adapter.myAddAll(data); //Your list will be udpdated!!!
ChrisF
  • 134,786
  • 31
  • 255
  • 325
AntuanSoft
  • 343
  • 2
  • 9
1

For me after changing information in sql database nothing could refresh list view( to be specific expandable list view) so if notifyDataSetChanged() doesn't help, you can try to clear your list first and add it again after that call notifyDataSetChanged(). For example

private List<List<SomeNewArray>> arrayList;
List<SomeNewArray> array1= getArrayList(...);
List<SomeNewArray> array2= getArrayList(...);
arrayList.clear();
arrayList.add(array1);
arrayList.add(array2);
notifyDataSetChanged();

Hope it makes sense for you.

Aivus
  • 502
  • 5
  • 15
1

If you want to maintain your scroll position when you refresh, and you can do this:

if (mEventListView.getAdapter() == null) {
    EventLogAdapter eventLogAdapter = new EventLogAdapter(mContext, events);
    mEventListView.setAdapter(eventLogAdapter);
} else {
    ((EventLogAdapter)mEventListView.getAdapter()).refill(events);
}

public void refill(List<EventLog> events) {
    mEvents.clear();
    mEvents.addAll(events);
    notifyDataSetChanged();
}

For the detail information, please see Android ListView: Maintain your scroll position when you refresh.

jww
  • 97,681
  • 90
  • 411
  • 885
Brandon Yang
  • 2,380
  • 1
  • 15
  • 6
1

You need to use a single object of that list whoose data you are inflating on ListView. If reference is change then notifyDataSetChanged() does't work .Whenever You are deleting elements from list view also delete them from the list you are using whether it is a ArrayList<> or Something else then Call notifyDataSetChanged() on object of Your adapter class.

So here see how i managed it in my adapter see below

public class CountryCodeListAdapter extends BaseAdapter implements OnItemClickListener{

private Context context;
private ArrayList<CountryDataObject> dObj;
private ViewHolder holder;
private Typeface itemFont;
private int selectedPosition=-1;
private ArrayList<CountryDataObject> completeList;

public CountryCodeListAdapter(Context context, ArrayList<CountryDataObject> dObj) {
    this.context = context;
    this.dObj=dObj;
    completeList=new  ArrayList<CountryDataObject>();
    completeList.addAll(dObj);
    itemFont=Typeface.createFromAsset(context.getAssets(), "CaviarDreams.ttf");
}

@Override
public int getCount() {
    return dObj.size();
}

@Override
public Object getItem(int position) {
    return dObj.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
    if(view==null){
        holder = new ViewHolder();
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        view = inflater.inflate(R.layout.states_inflator_layout, null);
        holder.textView = ((TextView)view.findViewById(R.id.stateNameInflator));
        holder.checkImg=(ImageView)view.findViewById(R.id.checkBoxState);
        view.setTag(holder);
    }else{
        holder = (ViewHolder) view.getTag();
    }
    holder.textView.setText(dObj.get(position).getCountryName());
    holder.textView.setTypeface(itemFont);

    if(position==selectedPosition)
     {
         holder.checkImg.setImageResource(R.drawable.check);
     }
     else
     {
         holder.checkImg.setImageResource(R.drawable.uncheck);
     }
    return view;
}
private class ViewHolder{
    private TextView textView;
    private ImageView checkImg;
}

public void getFilter(String name) {
    dObj.clear();
    if(!name.equals("")){
    for (CountryDataObject item : completeList) {
        if(item.getCountryName().toLowerCase().startsWith(name.toLowerCase(),0)){
            dObj.add(item);
        }
    }
    }
    else {
        dObj.addAll(completeList);
    }
    selectedPosition=-1;
    notifyDataSetChanged();
    notifyDataSetInvalidated(); 
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) {
    Registration reg=(Registration)context;
    selectedPosition=position;
    reg.setSelectedCountryCode("+"+dObj.get(position).getCountryCode());
    notifyDataSetChanged();
}
}
ADM
  • 20,406
  • 11
  • 52
  • 83
1

Just use myArrayList.remove(position); inside a listener:

  myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override public void onItemClick(AdapterView<?> parent, android.view.View view, int position, long id) {
           myArrayList.remove(position);
           myArrayAdapter.notifyDataSetChanged();
        }
    });
Steffo Dimfelt
  • 870
  • 12
  • 11
1

Consider you have passed a list to your adapter.
Use:

list.getAdapter().notifyDataSetChanged()

to update your list.

Mahdi-Malv
  • 16,677
  • 10
  • 70
  • 117
0

If you want to update the UI listview from a service, then make the adapter static in your Main activity and do this:

@Override
public void onDestroy() {
    if (MainActivity.isInFront == true) {
        if (MainActivity.adapter != null) {
            MainActivity.adapter.notifyDataSetChanged();
        }

        MainActivity.listView.setAdapter(MainActivity.adapter);
    }
}    
Ziem
  • 6,579
  • 8
  • 53
  • 86
Mayank Saini
  • 3,017
  • 24
  • 25
0

I was not able to get notifyDataSetChanged() to work on updating my SimpleAdapter, so instead I tried first removing all views that were attached to the parent layout using removeAllViews(), then adding the ListView, and that worked, allowing me to update the UI:

LinearLayout results = (LinearLayout)findViewById(R.id.results);
ListView lv = new ListView(this);
ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
SimpleAdapter adapter = new SimpleAdapter( this, list, R.layout.directory_row, 
                new String[] { "name", "dept" }, new int[] { R.id.name, R.id.dept } );

for (...) { 
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("name", name);
    map.put("dept", dept);
    list.add(map);
}

lv.setAdapter(adapter);
results.removeAllViews();     
results.addView(lv);
Chasden
  • 161
  • 1
  • 4
0

while using SimpleCursorAdapter can call changeCursor(newCursor) on the adapter.

Vihaan Verma
  • 12,815
  • 19
  • 97
  • 126
0

I was the same when, in a fragment, I wanted to populate a ListView (in a single TextView) with the mac address of BLE devices scanned over some time.

What I did was this:

public class Fragment01 extends android.support.v4.app.Fragment implements ...
{
    private ListView                listView;
    private ArrayAdapter<String>    arrayAdapter_string;

...

@Override
public void onActivityCreated(Bundle savedInstanceState)
{
    ...
    this.listView= (ListView) super.getActivity().findViewById(R.id.fragment01_listView);
    ...
    this.arrayAdapter_string= new ArrayAdapter<String>(super.getActivity(), R.layout.dispositivo_ble_item, R.id.fragment01_item_textView_titulo);
    this.listView.setAdapter(this.arrayAdapter_string);
}


@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)
{
    ...
    super.getActivity().runOnUiThread(new RefreshListView(device));
}


private class RefreshListView implements Runnable
{
    private BluetoothDevice bluetoothDevice;

    public RefreshListView(BluetoothDevice bluetoothDevice)
    {
        this.bluetoothDevice= bluetoothDevice;
    }

    @Override
    public void run()
    {
        Fragment01.this.arrayAdapter_string.add(new String(bluetoothDevice.toString()));
        Fragment01.this.arrayAdapter_string.notifyDataSetChanged();
    }
}

Then the ListView began to dynamically populate with the mac address of the devices found.

jsanmarb
  • 906
  • 12
  • 14
0

I think it depends on what you mean by refresh. Do you mean that the GUI display should be refreshed, or do you mean that the child views should be refreshed such that you can programatically call getChildAt(int) and get the view corresponding to what is in the Adapter.

If you want the GUI display refreshed, then call notifyDataSetChanged() on the adapter. The GUI will be refreshed when next redrawn.

If you want to be able to call getChildAt(int) and get a view that reflects what is what is in the adapter, then call to layoutChildren(). This will cause the child view to be reconstructed from the adapter data.

dazed
  • 352
  • 3
  • 9
0

I had an ArrayList which I wanted to display in a listview. ArrayList contained elements from mysql. I overrided onRefresh method and in that method I used tablelayout.removeAllViews(); and then repeated the process for getting data again from the database. But before that make sure to clear your ArrayList or whatever data structre or else new data will get appended to the old one..

CodeSsscala
  • 729
  • 3
  • 11
  • 23
0

If you are going by android guide lines and you are using the ContentProviders to get data from Database and you are displaying it in the ListView using the CursorLoader and CursorAdapters ,then you all changes to the related data will automatically be reflected in the ListView.

Your getContext().getContentResolver().notifyChange(uri, null); on the cursor in the ContentProvider will be enough to reflect the changes .No need for the extra work around.

But when you are not using these all then you need to tell the adapter when the dataset is changing. Also you need to re-populate / reload your dataset (say list) and then you need to call notifyDataSetChanged() on the adapter.

notifyDataSetChanged()wont work if there is no the changes in the datset. Here is the comment above the method in docs-

/**
 * Notifies the attached observers that the underlying data has been changed
 * and any View reflecting the data set should refresh itself.
 */
Sanjeet A
  • 5,171
  • 3
  • 23
  • 40
0

I was only able to get notifyDataSetChanged only by getting new adapter data, then resetting the adapter for the list view, then making the call like so:

    expandableAdapter = baseFragmentParent.setupEXLVAdapter();
    baseFragmentParent.setAdapter(expandableAdapter);
    expandableAdapter.notifyDataSetChanged(); 
Kristy Welsh
  • 7,828
  • 12
  • 64
  • 106
0

on other option is onWindowFocusChanged method, but sure its sensitive and needs some extra coding for whom is interested

 override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)

       // some controls needed
        programList = usersDBHelper.readProgram(model.title!!)
        notesAdapter = DailyAdapter(this, programList)
        notesAdapter.notifyDataSetChanged()
        listview_act_daily.adapter = notesAdapter
    }
Samir
  • 6,405
  • 5
  • 39
  • 42
0

If I talked about my scenario here, non of above answers will not worked because I had activity that show list of db values along with a delete button and when a delete button is pressed, I wanted to delete that item from the list.

The cool thing was, I did not used recycler view but a simple list view and that list view initialized in the adapter class. So, calling the notifyDataSetChanged() will not do anything inside the adapter class and even in the activity class where adapter object is initialized because delete method was in the adapter class.

So, the solution was to remove the object from the adapter in the adapter class getView method(to only delete that specific object but if you want to delete all, call clear()).

To you to get some idea, what was my code look like,

public class WordAdapter extends ArrayAdapter<Word> {
  Context context;

  public WordAdapter(Activity context, ArrayList<Word> words) {}
    //.......

    @NonNull
    @Override
    public View getView(final int position, View convertView, ViewGroup group) {
      //.......
     ImageButton deleteBt = listItemView.findViewById(R.id.word_delete_bt);
     deleteBt.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             if (vocabDb.deleteWord(currentWord.id)) {
                //.....
             } else{
                //.....
             }
             remove(getItem(position)); // <---- here is the trick ---<
             //clear() // if you want to clear everything
         }
    });
 //....

Note: here remove() and getItem() methods are inherit from the Adapter class.

  • remove() - to remove the specific item that is clicked
  • getItem(position) - is to get the item(here, thats my Word object that I have added to the list) from the clicked position.

This is how I set the adapter to the listview in the activity class,

    ArrayList<Word> wordList = new ArrayList();
    WordAdapter adapter = new WordAdapter(this, wordList);

    ListView list_view = (ListView) findViewById(R.id.activity_view_words);
    list_view.setAdapter(adapter);
Blasanka
  • 21,001
  • 12
  • 102
  • 104
0

After adding/deleting dynamic data in your "dataArray" do:

if you use an ArrayAdapter
adapter.notifyDataSetChanged();
if you use a customAdapter that extends ArrayAdapter
adapter.clear();
adapter.addAll(dataArray);
adapter.notifyDataSetChanged();
if you use a customAdapter that extends BaseAdapter
adapter.clear();
adapter.getData().addAll(dataArray);
adapter.getData().notifyDataSetChanged();
0

After deleting data from list view, you have to call refreshDrawableState(). Here is the example:

final DatabaseHelper db = new DatabaseHelper (ActivityName.this);

db.open();

db.deleteContact(arg3);

mListView.refreshDrawableState();

db.close();

and deleteContact method in DatabaseHelper class will be somewhat looks like

public boolean deleteContact(long rowId) {

   return db.delete(TABLE_NAME, BaseColumns._ID + "=" + rowId, null) > 0;

}
Ant4res
  • 1,217
  • 1
  • 18
  • 36
-1

The easiest is to just make a new Adaper and drop the old one:

myListView.setAdapter(new MyListAdapter(...));
user1712200
  • 329
  • 5
  • 8