Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error using notifyDataSetChanged in android array adapter

11-06 19:52:25.958: E/AndroidRuntime(29609): 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.ListPopupWindow$DropDownListView) with Adapter(class com.example.parkfoxxlight_android.PlacesAutoCompleteAdapter)]

Full log: http://pastebin.com/Hx7k28Rm

Full code of adapter: http://pastebin.com/TfH1bXE3 I am using the example from https://developers.google.com/places/training/autocomplete-android and it has quite the default code so it seems there is a bug in the google code?

The app crashes only sometimes with the above error message.

protected void publishResults(CharSequence constraint,
        FilterResults results) {

    if (results != null && results.count > 0) {
        notifyDataSetChanged();
    } else {
        notifyDataSetInvalidated();
    }
}

Activity http://pastebin.com/FYzYtvXY:

public class CityActivity extends Activity{

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

            AutoCompleteTextView autoCompView = (AutoCompleteTextView) findViewById(R.id.autocomplete_city);

            PlacesAutoCompleteAdapter ad = new PlacesAutoCompleteAdapter(this);
            ProgressBar b = (ProgressBar)findViewById(R.id.progressBar1);
            ad.setLoadingIndicator(b);

            autoCompView.setAdapter(ad);
        }
}

Any ideas how to fix this? I am on android 4.3.

like image 726
UpCat Avatar asked Nov 06 '13 19:11

UpCat


1 Answers

The Filter's performFiltering() method runs on a background thread and from that method you're changing the resultList on which your adapter is based. If you change that list of data and in that time the ListView access the adapter it will see that something has changed without its knowledge(and it will not be happy). You should avoid using the resultList in the performFiltering method and simply create a new temporary list:

// in the performFiltering method which runs on a background thread:
@Override
protected FilterResults performFiltering(CharSequence constraint) {
     FilterResults filterResults = new FilterResults();
     ArrayList<String> queryResults;
     if (constraint != null && constraint.length() > 0) {
         queryResults = autocomplete(constraint);
     } else {
         queryResults = new ArrayList<String>(); // empty list/no suggestions showing if there's no valid constraint
     }
     filterResults.values = queryResults;
     filterResults.count = queryResults.size();
     return filterResults; // ## Heading ##
}

private List<String> autocomplete(String input) {
   // don't use the here the resultList List on which the adapter is based!
   // some custom code to get items from http connection
     ArrayList<String> queryResults = new ArrayList<String>(); // new list
     queryResults.add("Some String");
     return queryResults;
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
     // update the data with the new set of suggestions
     resultList = (ArrayList<String>)results.values;
     if (results.count > 0) {
         notifyDataSetChanged();
     } else {
         notifyDataSetInvalidated();
     }
}
like image 115
user Avatar answered Oct 21 '22 14:10

user