IllegalStateException: The content of the adapter has changed but ListView did not receive a notification

android, android-arrayadapter, filter

Solution

Change publishResults to

@Override 
protected void publishResults(final CharSequence contraint, final FilterResults filterResults) { 
    listTempPrefix = (List) results.values;
    if(filterResults != null && filterResults.count > 0) {
        notifyDataSetChanged();
    } else {
        notifyDataSetInvalidated();
    }
}

This way the GUI thread updates the results instead of performFiltering which runs in a background thread.

Remove listTempPrefix references from performFiltering and use a local variable there to store the results and return them through FilterResults

Problem

I'm using a custom ArrayAdapter to set the adapter on an AutocompleteTextView (AddressAdapter extends ArrayAdapter). ``` public class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable { private ArrayList<String> mData; ArrayList<String> listTempPrefix = new ArrayList<String>(); ArrayList<String> listTemp = new ArrayList<String>(); String valueText; String[] words; String ulcase; public AutoCompleteAdapter(Context context, int textViewResourceId, ArrayList<String> bS) { super(context, textViewResourceId); mData = bS;//new ArrayList<String>(); } @Override public int getCount() { synchronized (listTempPrefix) { return listTempPrefix.size(); } } @Override public String getItem(int index) { synchronized (listTempPrefix) { try { //Log.e("Error", listTempPrefix.get(index)); return listTempPrefix.get(index); } catch(IndexOutOfBoundsException e) { Log.e("Error", "IndexOutOfBoundsException"); return ""; } } } @Override public Filter getFilter() { Filter myFilter = new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults filterResults = new FilterResults(); synchronized (filterResults) { listTempPrefix.clear(); listTemp.clear(); //Log.e("1", "1"); try { if(constraint != null) { // A class that queries a web API, parses the data and returns an ArrayList<Style> //StyleFetcher fetcher = new StyleFetcher(); //try { //mData = fetcher.retrieveResults(constraint.toString()); //} //catch(Exception e) {} // Now assign the values and count to the FilterResults object for(String value: mData) { valueText = value.toLowerCase(); //System.out.println("constraintH - " + constraint); constraint.toString().toLowerCase(); ulcase = constraint.toString().toLowerCase(); //System.out.println("ulcase - " + ulcase); if (valueText.startsWith(ulcase)) { listTempPrefix.add(value); } else { words = valueText.split(" "); //final int wordCount = words.length; // Start at index 0, in case valueText starts with space(s) for (int k = 0; k < words.length; k++) { if (words[k].startsWith(ulcase)) { listTemp.add(value); break; } } } ///listTemp.add(mData.get(i)); //filterResults.count = mData.size(); // System.out.println("mData" + i + mData.get(i)); } //Log.e("2", "2"); // System.out.println("size " + listTemp.size() + " value" + listTemp); listTempPrefix.addAll(listTemp); filterResults.values = listTempPrefix; filterResults.count = listTempPrefix.size(); //System.out.println("size " + filterResults.count + " value" + filterResults.values); //System.out.println("constraint" + constraint); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return filterResults; } } @Override protected void publishResults(CharSequence contraint, FilterResults filterResults) { synchronized (filterResults) { if(filterResults != null && filterResults.count > 0) { notifyDataSetChanged(); //Log.e("notifyDataSetChanged", "notifyDataSetChanged"); } else { notifyDataSetInvalidated(); //Log.e("notifyDataSetInvalidated", "notifyDataSetInvalidated"); } } } }; return myFilter; } ``` } What I got sometimes: please notice, it happens really rarely. But I'd like to get rid of this bug completely. Here is partial stacktrace: ``` java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(-1, class android.widget.AutoCompleteTextView$DropDownListView) with Adapter(class com.example.test.AutoCompleteAdapter)]. ``` The problem maybe that the fast input from keybord, method notifyDataSetChanged () issn't call. But i'am not sure.

Original source