android 修改listview中adapter數據時拋出異常java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification問題


近日在做項目時遇到非必現crush,具體異常信息為:

// Short Msg: java.lang.IllegalStateException

 

// Long Msg: 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(2131624004, class android.widget.ListView) with Adapter(class com.baidu.smartcalendar.widget.cx)]

 

// Build Label: Coolpad/pxa1088dkb_def/8750:4.2.1/JOP40D/4.2.063.P1.131218.8750:user/release-keys

 

// Build Changelist: 4.2.016.P1.8750

 

// Build Time: 1387361194000

 

// 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(2131624004, class android.widget.ListView) with Adapter(class com.baidu.smartcalendar.widget.cx)]

 

// at android.widget.ListView.layoutChildren(ListView.java:1559)

 

// at android.widget.AbsListView.onTouchModeChanged(AbsListView.java:3313)

 

// at android.view.ViewTreeObserver.dispatchOnTouchModeChanged(ViewTreeObserver.java:712)

 

// at android.view.ViewRootImpl.ensureTouchModeLocally(ViewRootImpl.java:3078)

 

// at android.view.ViewRootImpl.ensureTouchMode(ViewRootImpl.java:3062)

 

// at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3206)

 

// at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3169)

 

// at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4300)

 

// at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4279)

 

// at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4371)

 

// at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:179)

 

// at android.os.MessageQueue.nativePollOnce(Native Method)

 

// at android.os.MessageQueue.next(MessageQueue.java:125)

 

// at android.os.Looper.loop(Looper.java:124)

 

// at android.app.ActivityThread.main(ActivityThread.java:5078)

 

// at java.lang.reflect.Method.invokeNative(Native Method)

 

// at java.lang.reflect.Method.invoke(Method.java:511)

 

// at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:856)

 

// at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:623)

 

// at dalvik.system.NativeStart.main(Native Method)

 

異常的描述是不要在其他線程中修改listview的adapter數據而在ui線程中進行刷新notifyDataSetChanged()。我們一般為adapter添加數據時常常使用activity類內部的全局變量,這時在外部或其他線程中更新數據時,如果不及時刷新listview,就會拋出上述異常。於是我去掉線程,直接在ui線程中更新數據,發現問題依然存在。

仔細查看代碼,我的代碼是這樣的:

private void prepareData(Calendar c) {
        mTodayList = new ArrayList<SCEvent>();
        mFutureList = new ArrayList<SCEvent>();
        mList = new ArrayList<SCEvent>();
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(System.currentTimeMillis());
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        ArrayList<SCEvent> list = SmartCalendarDB.getInstance(getActivity())
                .getBirthdayLatest2(mCalendar.getTimeInMillis(),
                        cal.getTimeInMillis() != mCalendar.getTimeInMillis());
        if(list != null && list.size() > 0) {
            int month = mCalendar.get(Calendar.MONTH) + 1;
            int day = mCalendar.get(Calendar.DAY_OF_MONTH);
            for(SCEvent e : list) {
                if(e.getmBirthdayMonth() == month && e.getmBirthdayDay() == day) {
                    mTodayList.add(e);
                } else {
                    mFutureList.add(e);
                }
            }
            if(mTodayList != null && mTodayList.size() > 0) {
                Collections.sort(mTodayList, new TimeComparator());
                for(SCEvent e : mTodayList) {
                    mList.add(e);
                }
                mList.add(null);
            }
            if(mFutureList != null && mFutureList.size() > 0) {
                if(mTodayList == null || mTodayList.size() <= 0) {
                    mList.add(null);
                }
                Collections.sort(mFutureList, new AdvanceComparator());
                boolean add = mList != null && mList.size() > 0;
                for(SCEvent e : mFutureList) {
                    mList.add(e);
                }
                if(!add) {
                    mList.add(null);
                }
            }
        }
        if(mList != null && mList.size() > 0) {
            mListView.setVisibility(View.VISIBLE);
            mEmptyLayout.setVisibility(View.GONE);
            mAdapter.notifyDataSetChanged();
        } else {
            mListView.setVisibility(View.GONE);
            mEmptyLayout.setVisibility(View.VISIBLE);
        }
    }

我的adapter數據是保存在mlist中,而在代碼中不斷的改變了mlist內部的數據,而只在最后調用了一次mAdapter.notifyDataSetChanged(),導致listview沒有及時刷新而拋出異常。

所以結論在使用listview時,及時不在非ui線程中更新adapter數據,也最好將數據直接定義在adapter類內部或在改變數據時要及時刷新listview,否則會拋出上述異常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM