Currently I have a form in which I have a AutoCompleteTextView element, to fill this View I have an adapter called AutoCompleteStoreAdapter in which, using the getFilter () method, I get the data from the GetAllStores class that extends from AsynkTask , this is because the data to fill the AutoCompleteTextView is obtained from a web service from whatever they write in the field.
I notice that when I start writing there is a slight delay between what I write and the list. When I write very fast, I erase the writing, I write something else, I delete it again and so on (to see the behavior of my field due to the delay it has), after doing this a few times, it throws me the following exception:
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. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(-1, class android.widget.DropDownListView) with Adapter(class mx.circuloinformador.qr.adapters.AutoCompleteStoreAdapter)]
I understand that I must notify the adapter of the changes with notifyDataSetChanged () but in this case, it loads the data asynchronously and only happens when I write and changed the AutoCompleteTextView content very fast, I can not find where could I call notifyDataSetChanged () and avoid the error.
AutoCompleteStoreAdapter
public class AutoCompleteStoreAdapter extends ArrayAdapter implements Filterable {
private ArrayList<Store> stores;
private AutoCompleteStoreAdapter adapter;
public AutoCompleteStoreAdapter(Context context, int resource) {
super(context, resource);
stores = new ArrayList<Store>();
adapter = this;
}
@Override
public int getCount() {
return stores.size();
}
@Override
public Store getItem(int position) {
return stores.get(position);
}
@Override
public Filter getFilter() {
Filter myFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if(constraint != null){
try{
String term = constraint.toString();
stores = new GetAllStores(adapter).execute(term).get();
} catch (NullPointerException e) {
stores = new ArrayList<Store>();
stores.add(new Store(0, "No válido", "No válido", 0, false, false));
notifyDataSetChanged();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
try {
filterResults.values = stores;
filterResults.count = stores.size();
} catch (NullPointerException e) {
stores = new ArrayList<Store>();
stores.add(new Store(0, "No válido", "No válido", 0, false, false));
filterResults.values = stores;
filterResults.count = stores.size();
notifyDataSetChanged();
}
}
return filterResults;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if(results != null && results.count > 0){
notifyDataSetChanged();
}else{
try {
notifyDataSetInvalidated();
} catch (NullPointerException e) {
stores = new ArrayList<Store>();
stores.add(new Store(0, "No válido", "No válido", 0, false, false));
notifyDataSetChanged();
}
}
}
};
return myFilter;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.auto_complete_stores_layout, parent, false);
Store store;
try {
store = stores.get(position);
} catch (IndexOutOfBoundsException e) {
store = stores.get(stores.size() - 1);
Log.e("[CI]", e.getMessage());
}
TextView storeName = (TextView) view.findViewById(R.id.lblStoreName);
storeName.setText(store.getName().toUpperCase());
return view;
}
}
GetAllStores
private class GetAllStores extends AsyncTask<String, String, ArrayList> {
private AutoCompleteStoreAdapter adapter;
public GetAllStores(AutoCompleteStoreAdapter adapter) {
this.adapter = adapter;
}
@Override
protected ArrayList<Store> doInBackground(String... strings) {
ArrayList<Store> stores = Store.getAllStoresByName(strings[0]);
return stores;
}
@Override
protected void onPostExecute(ArrayList arrayList) {
Log.i("[CI]", "Se descargaron todos los extablecimientos");
this.adapter.notifyDataSetChanged();
}
}
Store.getAllStoresByName (strings [0]); only gets the data from a web service, so I do not think it necessary to put the code as well.