notifyDataSetChange not working from custom adapter

AndroidListviewBaseadapterNotifydatasetchanged

Android Problem Overview


When I repopulate my ListView, I call a specific method from my Adapter.

Problem:

When I call updateReceiptsList from my Adapter, the data is refreshed, but my ListView doesn't reflect the change.

Question:

Why doesn't my ListView show the new data when I call notifyDataSetChanged?

Adapter:

public class ReceiptListAdapter extends BaseAdapter {

	public List<Receipt> receiptlist;
	private Context context;
	private LayoutInflater inflater;
	private DateHelpers dateH;

	public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
		context = mcontext;
		receiptlist = rl;
		Collections.reverse(receiptlist);
		inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		dateH = new DateHelpers();
	}

	@Override
	public int getCount() {
		try {
			int size = receiptlist.size();
			return size;
		} catch(NullPointerException ex) {
			return 0;
		}
	}
	
	public void updateReceiptsList(List<Receipt> newlist) {
		receiptlist = newlist;
		this.notifyDataSetChanged();
	}

	@Override
	public Receipt getItem(int i) {
		return receiptlist.get(i);
	}

	@Override
	public long getItemId(int i) {
		return receiptlist.get(i).getReceiptId() ;
	}

	private String getPuntenString(Receipt r) {
		if(r.getPoints().equals("1")) {
			return "1 punt";
		}
		return r.getPoints()+" punten";
	}

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

		final Receipt receipt = receiptlist.get(position);
		ReceiptViewHolder receiptviewholder;
		Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");        
		Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");
    
		if (vi == null) { //convertview==null
			receiptviewholder = new ReceiptViewHolder();
			vi = inflater.inflate(R.layout.view_listitem_receipt, null);
			vi.setOnClickListener(null);
			vi.setOnLongClickListener(null);
			vi.setLongClickable(false);
			receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
			receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
			receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
			receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
			receiptviewholder.shop.setTypeface(tf_hn_bold);
			receiptviewholder.price.setTypeface(tf_hn_bold);
			vi.setTag(receiptviewholder);
		}else{//convertview is not null
			receiptviewholder = (ReceiptViewHolder)vi.getTag();
		}

		receiptviewholder.shop.setText(receipt.getShop());
		receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
		receiptviewholder.price.setText("€ "+receipt.getPrice());
		receiptviewholder.points.setText(getPuntenString(receipt));

		vi.setClickable(false);
		return vi;
	}

	public static class ReceiptViewHolder {
		public TextView shop;
		public TextView date;
		public TextView price;
		public TextView points;
	}

	public Object getFilter() {
		// XXX Auto-generated method stub
		return null;
	}

}

--EDIT:

found Workaround

Just to have some functional code i do now:

listview.setAdapter( new ReceiptListAdapter(activity,mcontext, -new dataset-);

Works, but not how it is supposed to work.

Android Solutions


Solution 1 - Android

Change your method from

public void updateReceiptsList(List<Receipt> newlist) {
    receiptlist = newlist;
    this.notifyDataSetChanged();
}

To

public void updateReceiptsList(List<Receipt> newlist) {
    receiptlist.clear();
    receiptlist.addAll(newlist);
    this.notifyDataSetChanged();
}

So you keep the same object as your DataSet in your Adapter.

Solution 2 - Android

I have the same problem, and i realize that. When we create adapter and set it to listview, listview will point to object somewhere in memory which adapter hold, data in this object will show in listview.

adapter = new CustomAdapter(data);
listview.setadapter(adapter);

if we create an object for adapter with another data again and notifydatasetchanged():

adapter = new CustomAdapter(anotherdata);
adapter.notifyDataSetChanged();

this will do not affect to data in listview because the list is pointing to different object, this object does not know anything about new object in adapter, and notifyDataSetChanged() affect nothing. So we should change data in object and avoid to create a new object again for adapter

Solution 3 - Android

As I have already explained the reasons behind this issue and also how to handle it in a different answer thread Here. Still i am sharing the solution summary here.

One of the main reasons notifyDataSetChanged() won't work for you - is,

Your adapter loses reference to your list.

When creating and adding a new list to the Adapter. Always follow these guidelines:

  1. Initialise the arrayList while declaring it globally.
  2. Add the List to the adapter directly with out checking for null and empty values . Set the adapter to the list directly (don't check for any condition). Adapter guarantees you that wherever you make changes to the data of the arrayList it will take care of it, but never loose the reference.
  3. Always modify the data in the arrayList itself (if your data is completely new than you can call adapter.clear() and arrayList.clear() before actually adding data to the list) but don't set the adapter i.e If the new data is populated in the arrayList than just adapter.notifyDataSetChanged()

Hope this helps.

Solution 4 - Android

Maybe try to refresh your ListView:

receiptsListView.invalidate().

EDIT: Another thought came into my mind. Just for the record, try to disable list view cache:

<ListView
    ...
    android:scrollingCache="false"
    android:cacheColorHint="@android:color/transparent"
    ... />

Solution 5 - Android

I had the same problem using ListAdapter

I let Android Studio implement methods for me and this is what I got:

public class CustomAdapter implements ListAdapter {
    ...
    @Override
    public void registerDataSetObserver(DataSetObserver observer) {

    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {

    }
    ...
}

The problem is that these methods do not call super implementations so notifyDataSetChange is never called.

Either remove these overrides manually or add super calls and it should work again.

@Override
public void registerDataSetObserver(DataSetObserver observer) {
    super.registerDataSetObserver(observer);
}

@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
    super.unregisterDataSetObserver(observer);
}

Solution 6 - Android

class StudentAdapter extends BaseAdapter {
    ArrayList<LichHocDTO> studentList;

    private void capNhatDuLieu(ArrayList<LichHocDTO> list){
        this.studentList.clear();
        this.studentList.addAll(list);
        this.notifyDataSetChanged();
    }
}

You can try. It work for me

Solution 7 - Android

If adapter is set to AutoCompleteTextView then notifyDataSetChanged() doesn't work.

Need this to update adapter:

myAutoCompleteAdapter = new ArrayAdapter<String>(MainActivity.this, 
        android.R.layout.simple_dropdown_item_1line, myList);
      
myAutoComplete.setAdapter(myAutoCompleteAdapter);

Refer: http://android-er.blogspot.in/2012/10/autocompletetextview-with-dynamic.html

Solution 8 - Android

If by any chance you landed on this thread and wondering why adapter.invaidate() or adapter.clear() methods are not present in your case then maybe because you might be using RecyclerView.Adapter instead of BaseAdapter which is used by the asker of this question. If clearing the list or arraylist not resolving your problem then it may happen that you are making two or more instances of the adapter for ex.:

MainActivity

...

adapter = new CustomAdapter(list);
adapter.notifyDataSetChanged();
recyclerView.setAdapter(adapter);

...

and
SomeFragment

...

adapter = new CustomAdapter(newList);
adapter.notifyDataSetChanged();

...

If in the second case you are expecting a change in the list of inflated views in recycler view then it is not gonna happen as in the second time a new instance of the adapter is created which is not attached to the recycler view. Setting notifyDataSetChanged in the second adapter is not gonna change the content of recycer view. For that make a new instance of the recycler view in SomeFragment and attach it to the new instance of the adapter.

SomeFragment

...

recyclerView = new RecyclerView();
adapter = new CustomAdapter();
recyclerView.setAdapter(adapter);

...

Although, I don't recommend making multiple instances of the same adapter and recycler view.

Solution 9 - Android

Add this code

runOnUiThread(new Runnable() { public void run() {
               adapter = new CustomAdapter(anotherdata);
            adapter.notifyDataSetChanged();
            }
        });

Solution 10 - Android

In my case I simply forget to add in my fragment mRecyclerView.setAdapter(adapter)

Solution 11 - Android

I made a very noob mistake that I was setting the adapter of RecyclerView before initialzing the adapter itself like this.

    // Assuume oneOffJobTasksListRVAdapter is declared already 
    recyclerView.setAdapter(oneOffJobTasksListRVAdapter);        
    oneOffJobTasksListRVAdapter = new OneOffJobTasksListRVAdapter();

Switching the lines fixed my issue.

    oneOffJobTasksListRVAdapter = new OneOffJobTasksListRVAdapter();
    recyclerView.setAdapter(oneOffJobTasksListRVAdapter);        

Solution 12 - Android

I have the same problem but I just finished it!!

you should change to

public class ReceiptListAdapter extends BaseAdapter {

    public List<Receipt> receiptlist;
    private Context context;
    private LayoutInflater inflater;
    private DateHelpers dateH;
    private List<ReceiptViewHolder> receiptviewlist;

    public ReceiptListAdapter(Activity activity, Context mcontext, List<Receipt> rl) {
        context = mcontext;
        receiptlist = rl;
        receiptviewlist = new ArrayList<>();
        receiptviewlist.clear();
        for(int i = 0; i < receiptlist.size(); i++){
          ReceiptViewHolder receiptviewholder = new ReceiptViewHolder();
          receiptviewlist.add(receiptviewholder);
        }
        Collections.reverse(receiptlist);
        inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        dateH = new DateHelpers();
    }

    @Override
    public int getCount() {
        try {
            int size = receiptlist.size();
            return size;
        } catch(NullPointerException ex) {
            return 0;
        }
    }

    public void updateReceiptsList(List<Receipt> newlist) {
        receiptlist = newlist;
        this.notifyDataSetChanged();
    }

    @Override
    public Receipt getItem(int i) {
        return receiptlist.get(i);
    }

    @Override
    public long getItemId(int i) {
        return receiptlist.get(i).getReceiptId() ;
    }

    private String getPuntenString(Receipt r) {
        if(r.getPoints().equals("1")) {
            return "1 punt";
        }
        return r.getPoints()+" punten";
    }

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

        final Receipt receipt = receiptlist.get(position);
        ReceiptViewHolder receiptviewholder;
        Typeface tf_hn = Typeface.createFromAsset(context.getAssets(), "helveticaneue.ttf");        
        Typeface tf_hn_bold = Typeface.createFromAsset(context.getAssets(), "helveticaneuebd.ttf");

        if (vi == null) { //convertview==null
            ReceiptViewHolder receiptviewholder = receiptviewlist.get(position);
            vi = inflater.inflate(R.layout.view_listitem_receipt, null);
            vi.setOnClickListener(null);
            vi.setOnLongClickListener(null);
            vi.setLongClickable(false);
            receiptviewholder.shop = (TextView) vi.findViewById(R.id.tv_listitemreceipt_shop);
            receiptviewholder.date = (TextView) vi.findViewById(R.id.tv_listitemreceipt_date);
            receiptviewholder.price = (TextView) vi.findViewById(R.id.tv_listitemreceipt_price);
            receiptviewholder.points = (TextView) vi.findViewById(R.id.tv_listitemreceipt_points);
            receiptviewholder.shop.setTypeface(tf_hn_bold);
            receiptviewholder.price.setTypeface(tf_hn_bold);
            vi.setTag(receiptviewholder);
        }else{//convertview is not null
            receiptviewholder = (ReceiptViewHolder)vi.getTag();
        }

        receiptviewholder.shop.setText(receipt.getShop());
        receiptviewholder.date.setText(dateH.timestampToDateString(Long.parseLong(receipt.getPurchaseDate())));
        receiptviewholder.price.setText("€ "+receipt.getPrice());
        receiptviewholder.points.setText(getPuntenString(receipt));

        vi.setClickable(false);
        return vi;
    }

    public static class ReceiptViewHolder {
        public TextView shop;
        public TextView date;
        public TextView price;
        public TextView points;
    }

    public Object getFilter() {
        // XXX Auto-generated method stub
        return null;
    }

}

Solution 13 - Android

My case was different but it might be the same case for others

for those who still couldn't find a solution and tried everything above, if you're using the adapter inside fragment then the reason it's not working fragment could be recreating so the adapter is recreating everytime the fragment recreate

you should verify if the adapter and objects list are null before initializing

if(adapter == null){
  adapter = new CustomListAdapter(...);
}
...

if(objects == null){
  objects = new ArrayList<>();
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJasperView Question on Stackoverflow
Solution 1 - AndroidtolgapView Answer on Stackoverflow
Solution 2 - AndroidNhan TranView Answer on Stackoverflow
Solution 3 - AndroidSazzad Hissain KhanView Answer on Stackoverflow
Solution 4 - AndroidRafal GałkaView Answer on Stackoverflow
Solution 5 - AndroidDavor ZlotrgView Answer on Stackoverflow
Solution 6 - AndroidDũng Phạm TiếnView Answer on Stackoverflow
Solution 7 - AndroidPrabsView Answer on Stackoverflow
Solution 8 - AndroidNeeraj SewaniView Answer on Stackoverflow
Solution 9 - AndroidShriKant AView Answer on Stackoverflow
Solution 10 - AndroidLoic JackotinView Answer on Stackoverflow
Solution 11 - AndroidMuhammad Bilal ahmadView Answer on Stackoverflow
Solution 12 - Android林權章View Answer on Stackoverflow
Solution 13 - AndroidFarido mastrView Answer on Stackoverflow