从Edittext搜索时出现IllegalStateException

时间:2014-08-22 13:17:33

标签: android listview filter illegalstateexception

我正在使用TextWatcher来过滤listview的结果。但我得到了以下错误:

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. with Adapter

我没有在任何地方使用后台线程。如何摆脱这个???

    @Override
    public Filter getFilter() {
        // TODO Auto-generated method stub

        Filter filter = new Filter() {

            @SuppressWarnings("unchecked")
            @Override
            protected  void publishResults(CharSequence constraint, FilterResults results) {

                contactNameList = (ArrayList<String>) results.values;
                //Log.e("RESULT:",results.values.toString() );
                //                    getActivity().runOnUiThread(new Runnable() {
                //                        public void run() {
                try {
                    if (results.count > 0) {
                        mContactListAdapter.notifyDataSetChanged();
                    } else {
                        mContactListAdapter.notifyDataSetInvalidated();
                    }  

                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
            }

            @Override
            protected synchronized FilterResults performFiltering(CharSequence constraint) {

                FilterResults results = new FilterResults();        // Holds the results of a filtering operation in values
                ArrayList<String> FilteredArrList = new ArrayList<String>();

                // set the Filtered result to return
                try {
                    String sql = "SELECT * FROM "
                            +MySQLiteHelper.TABLE_NAME_CONTACT
                            +" WHERE "
                            +MySQLiteHelper.COLUMN_CNT_NICK_NAME
                            +" LIKE '"+constraint.toString()+"%'"
                            +" ORDER BY "
                            +(prefs.getOrderBy().equalsIgnoreCase("")? MySQLiteHelper.COLUMN_CNT_NICK_NAME: prefs.getOrderBy()) 
                            +" COLLATE NOCASE;";                                      

                    Log.e("FILTER SQL ",sql);
                    synchronized (this) {
                        fetchContactData(sql);            
                    }


                    results.count = contactNameList.size();
                    results.values = contactNameList;
                    return results;

                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }
                return null;                
            }
        };
        return filter;            
    }

EDIT -Whole logcat:

E/onQueryTextChange(17748): contact onTextChanged:p 08-22 19:18:10.035: E/FILTER SQL(17748): SELECT * FROM contacts WHERE cnt_nick LIKE 'p%' ORDER BY cnt_nick COLLATE NOCASE; 08-22 19:18:10.047: D/AndroidRuntime(17748): Shutting down VM 08-22 19:18:10.048: W/dalvikvm(17748): threadid=1: thread exiting with uncaught exception (group=0x418aa9a8) 08-22 19:18:10.060: E/AndroidRuntime(17748): FATAL EXCEPTION: main 08-22 19:18:10.060: E/AndroidRuntime(17748): 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(2131492994, class android.widget.ListView) with Adapter(class com.ecosmob.contactpro.contacts.ContactFragment$ContactListAdapter)] 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.ListView.layoutChildren(ListView.java:1559) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.AbsListView.onLayout(AbsListView.java:2052) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1021) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1589) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1670) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1528) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.LinearLayout.onLayout(LinearLayout.java:1441) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:690) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1670) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1528) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.LinearLayout.onLayout(LinearLayout.java:1441) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.widget.FrameLayout.onLayout(FrameLayout.java:448) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.View.layout(View.java:14118) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewGroup.layout(ViewGroup.java:4467) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2183) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1947) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1139) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4893) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:776) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.Choreographer.doCallbacks(Choreographer.java:579) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.Choreographer.doFrame(Choreographer.java:548) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:762) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.os.Handler.handleCallback(Handler.java:800) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.os.Handler.dispatchMessage(Handler.java:100) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.os.Looper.loop(Looper.java:194) 08-22 19:18:10.060: E/AndroidRuntime(17748): at android.app.ActivityThread.main(ActivityThread.java:5426) 08-22 19:18:10.060: E/AndroidRuntime(17748): at java.lang.reflect.Method.invokeNative(Native Method) 08-22 19:18:10.060: E/AndroidRuntime(17748): at java.lang.reflect.Method.invoke(Method.java:525) 08-22 19:18:10.060: E/AndroidRuntime(17748): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842) 08-22 19:18:10.060: E/AndroidRuntime(17748): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609) 08-22 19:18:10.060: E/AndroidRuntime(17748): at dalvik.system.NativeStart.main(Native Method)

编辑 - 2(SearchBox编辑文字):

searchBox.addTextChangedListener(new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // TODO Auto-generated method stub

        }
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,int after) {
            // TODO Auto-generated method stub
            //Log.e("onQueryTextChange","contact beforeTextChanged:"+ s);    
        }
        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub
            //Log.e("onQueryTextChange","contact afterTextChanged:"+ s);
            try{
                searchText = s.toString();
                if(searchText.length() > 0){
                    mContactListAdapter.getFilter().filter(searchText);    

                }
            }catch(Exception e){
                e.printStackTrace();
            }
            Log.e("onQueryTextChange","contact onTextChanged:"+ s);
        }
    });

2 个答案:

答案 0 :(得分:0)

您的代码的某些部分对我没有意义。在performFiltering方法中,您有以下几行:

results.count = contactNameList.size(); 
results.values = contactNameList;

然后在publishResults中,您有以下一行:

contactNameList = (ArrayList<String>) results.values;

我认为您更新contactNameList的唯一地方是fetchContactData方法。在后台线程中调用此方法。我相信您在适配器中使用contactNameList。同样。这就是你得到这个错误的原因。请尝试以下方法:

private ArrayList<String> fetchContactData(String query) {
    //Do your query here but DO NOT update contactNameList
    return <the arrayList>
}

然后在performFiltering中替换以下行:

synchronized (this) {
       fetchContactData(sql);            
}

results.count = contactNameList.size(); 
results.values = contactNameList;

用这个:

ArrayList<String> temp;
synchronized (this) {
       temp = fetchContactData(sql);            
}

results.count = temp.size(); 
results.values = temp;

应该做的伎俩

答案 1 :(得分:0)

我认为问题是在searchBox中添加快速字符时;它会过快地在数组中获取联系人。意味着notifyDatasetChanged()没有足够的时间来被召唤。所以,我以下面的解决方案结束了:

 searchBox.addTextChangedListener(new TextWatcher() {

        private final int TRIGGER_SERACH = 1;
        private final long SEARCH_TRIGGER_DELAY_IN_MS = 300;  

        private Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == TRIGGER_SERACH) {  
                    try{
                        //if(searchText.length() > 0){  
                            mContactListAdapter.getFilter().filter(searchText);                             
                        //}
                    }catch(Exception e){
                        e.printStackTrace(); 
                    }
                }
            }
        };

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // TODO Auto-generated method stub

        }  
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,int after) {
            // TODO Auto-generated method stub
            //Log.e("onQueryTextChange","contact beforeTextChanged:"+ s);   
        }
        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub
            //Log.e("onQueryTextChange","contact afterTextChanged:"+ s);
            searchText = s.toString();
            handler.removeMessages(TRIGGER_SERACH);
            handler.sendEmptyMessageDelayed(TRIGGER_SERACH, SEARCH_TRIGGER_DELAY_IN_MS);
            Log.e("onQueryTextChange","contact onTextChanged:"+ s);        
        }
    });

这将等待用户输入单词,然后才开始搜索。