近日在做项目时遇到非必现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,否则会抛出上述异常。
android
修改listview中adapter数据时抛出异常java.lang.IllegalStateException: The content of the
adapter has changed but ListView did not receive a notification问题