异常描述
E/AndroidRuntime(23093): 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.
字面意思:adapter的内容已经改变,但是ListView并没有收到通知,请确定adapter的内容是否在后台线程(非UI线程)进行了更新。
代码所处环境:开一条新线程连接网络,把服务端返回的数据然存在myArr中,最后使用handler消息通知机制来通知UI主线程,更新UI。
原因及解决方案
出现异常的原因:网络线程可能没有结束(没到handler处理消息函数中),就提前切换到主线程,此时数据源myArr已经不为空,主线程认为数据源加载完毕,会跳到adapter的getView函数中,更新adapter,但并没有通知ListView通知数据源发生变化。
解决方法思路:把数据源的变化、adapter的变化和ListView的变化都放在UI线程中。即把myArr仅作为接收网络数据的buffer,把myArrNew作为数据源。当myArr在其它线程加载完网络数据后(长度不再变化),回调到UI线程,把myArr的内容存到数据源myArrNew,该数据源不再变化,并通知ListView刷新。
再开一个存数据的myArrNew,代码如下
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case NET_SUCCESS:
myArrNew = myArr;
m_adapter.notifyDataSetChanged();
if (startnid != 0) {
m_listView.setPullLoadEnable(true);
}
break;
default:
break;
}
}
}
Android ListView控件简介
ListView定义:ListView控件用于以列表的形式来显示数据。该控件采用了MVC模式将前端显示和后端数据进行分离。也就是说,ListView控件在装载数据时,并不是直接使用ListView类的add方法或类似方法添加数据,而是需要一个Adapter对象来为ListView整体适配数据源,进而由ListView展示。这种模式即典型的MVC模式,Adapter对象相当于MVC模式中得C(Control);ListView相当于MVC模式当中的V(View);为ListView提供数据的数组相当于MVC模式中得M(model)。