应用程序因 ANR::IllegalStateException 崩溃:适配器的内容已更改但 ListView 未收到通知。

application crashed with ANR:: IllegalStateException: The content of the adapter has changed but ListView did not receive a notification.

我用适配器创建了一个列表视图。使用过滤器实现搜索。它工作正常。但有时应用程序会因以下错误而崩溃:

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.

在 ListView activity 中,当用户在文本框中键入内容时,我使用以下代码调用搜索。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.list_view_layout);
    mAdapter = new ListViewAdapter(this);
    ...

    mSearchEditText = (EditText) findViewById(R.id.search_text);
    mSearchEditText.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            Log.v("ListViewActivity", "SearchTextBox: onTextChanged <" + s + ">");
            mAdapter.getFilter().filter(s);
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });

在ListViewAdapter中我使用过滤器实现了listview中的搜索:

public class ListViewAdapter extends BaseAdapter implements Filterable{
private ArrayList<ListItem> mOriginalList;
private ArrayList<ListItem> mDisplayedList;

...

@Override
public Filter getFilter() {
    Filter filter = new Filter() {

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            Log.v("ListViewAdapter", "Filter: publishResults constraint<" + constraint + ">");
            notifyDataSetChanged();
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            Log.v("ListViewAdapter", "Filter: performFiltering constraint<" + constraint + ">");
            FilterResults filterResults = new FilterResults();

            mDisplayedList.clear();

            if (constraint == null || constraint.length() == 0) {
                mDisplayedList.addAll(mOriginalList);
                filterResults.count = mDisplayedList.size();
                filterResults.values = mDisplayedList;
            } else {
                String searchText = constraint.toString().toLowerCase();
                for (ListItem listItem : mOriginalList) {
                    if (listItem.getKeyName().toLowerCase().contains(searchText) 
                            || listItem.getKeyValue().toLowerCase().contains(searchText)) {
                        mDisplayedList.add(listItem);
                    }
                }

                filterResults.count = mDisplayedList.size();
                filterResults.values = mDisplayedList;
            }

            Log.v("ListViewAdapter", "Filter: performFiltering filterResults.count<" + filterResults.count + ">");
            return filterResults;
        }
    };

    return filter;
}

使用:mAdapter.notifyDataSetChanged();

onTextChanged中调用mAdapter.notifyDataSetChanged().

 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.

出现此问题是因为您将适配器设置在主线程上。而不是您需要在 UI thread 中设置您的适配器。与 AsyncTask 一样,在 onPostExecute() 方法或 onHandledMessage() 方法中使用 HandlerThread.

设置适配器

问题已解决。我移动了代码以将 mDisplayedList 更新为 publishResults() 而不是在 performFiltering() for 循环中继续更新。更新 mDisplayedList 并一起调用 notifyDataSetChanged()。我认为这是最好的解决方案。

@Override
public Filter getFilter() {
    Filter filter = new Filter() {

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            Log.v("ListViewAdapter", "Filter: publishResults constraint<" + constraint + ">");

            if (results.count == 0) {
                mDisplayedList.clear();
                notifyDataSetInvalidated();
            } else {
                mDisplayedList.clear();
                mDisplayedList.addAll((ArrayList<ListItem>) results.values);
                notifyDataSetChanged();
            }
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            Log.v("ListViewAdapter", "Filter: performFiltering constraint<" + constraint + ">");
            FilterResults filterResults = new FilterResults();
            ArrayList<ListItem> filteredList = new ArrayList<ListItem>();

            if (constraint == null || constraint.length() == 0) {
                filteredList.addAll(mOriginalList);
            } else {
                String searchText = constraint.toString().toLowerCase();
                for (ListItem listItem : mOriginalList) {
                    if (listItem.getKeyName().toLowerCase().contains(searchText) 
                            || listItem.getKeyValue().toLowerCase().contains(searchText)) {
                        filteredList.add(listItem);
                    }
                }
            }

            filterResults.count = filteredList.size();
            filterResults.values = filteredList;
            Log.v("ListViewAdapter", "Filter: performFiltering filterResults.count<" + filterResults.count + ">");
            return filterResults;
        }
    };

    return filter;
}