|字号订阅

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.

相信有不少android初学者在运用ListView和Adapter时发生了上述的异常。一般情况下,上述异常一般发生在我们启动一个后台线程加载数据,同时在主线程(即UI线程)刷新ListView在显示新加载的内容。我们的做法一般是:在后台线程中把加载的数据放入到一个List中,而在主线程中实例化Adapter,这个Adapter中所用到的List正是在后台线程中加载的那个List。

发生上述异常的代码思路是这样子的,请看代码:

首先,我们定义一个List全局变量,后台线程中加载的数据就放到这个list中(请注意我标了红色的list变量,问题就出在它身上):

private List<Map<String,Object>>list= null;

接着,我们会启动一个后台线程,用于加载数据:

class GetDataThread implements Runnable{//单独启动一个线程用于加载歌曲列表

@Override
public void run() {
list= new ArrayList<Map<String,Object>>();

//然后把搜索出来的数据放入到list中。

}
}

最后,我们会在主线程中刷新界面,刷新界面的代码,我们是要放到handler中处理的:

class RefreshLocalMusicListThread implements Runnable{

@Override
public void run() {
local_lv = (ListView)findViewById(R.id.local_musiclist);

SimpleAdapter adapter = new SimpleAdapter(LocalActivity.this,list,R.layout.local_music_list,new String[] {"local_name","local_size"}, new int[]{R.id.local_name,R.id.local_size});
local_lv.setAdapter(adapter);
LocalActivity.this.registerForContextMenu(local_lv);
handler.postDelayed(refreshThread, 10);

}

}

以上的思路,是会发生上述异常的!下面请看我的分析:

当执行 SimpleAdapter adapter = new SimpleAdapter(LocalActivity.this,list,R.layout.local_music_list,new String[] {"local_name","local_size"}, new int[]{R.id.local_name,R.id.local_size});时集合list中数据与我们的listView是绑定在一起的了。此时,,假如list中的数据有5条,即list.size()==5,这时与listView绑定的就是5条数据。但是,我们的后台线程还在运行,list中的数据会发生变化,然而我们的listView认定的就是之前只有5条数据的list,但是这时的list中的数据已经不是5条了,就是这个冲突导致了上述的异常!!!

网上有这样一种解决方法(实际上解决不了问题):

在 adapter.notifyDataSetChanged() 之前调用listview.setVisibility(View.GONE);在adapter.notifyDataSetChanged() 之后调用listview.setVisibility(View.VISIBLE)

但是这是错误的!!!
正确的解决方法是这样的:

既然与listView绑定了的list发生了变化而没来得及通知listView导致了上述的异常,那我们就针对这一点,只要listView与list绑定后,在listView显示之前不要让list发现变化就行了。做法有很多种,我个人的做法是这样子的:

首先,定义一个独立的List:

private List<Map<String,Object>> data = null;

接着,在onCreate或者onResume中初始化它(当然,你也可以在每次用到它的时候初始化它,不过这样子会初始化很多歌对象,浪费内存,不推荐):

data = new ArrayList<Map<String,Object>>();

然后,在创建adapter之前,把list中数据放入到集合data中,注意千万不要直接赋值:data = list(这是错误的,因为这样data也指向了list所在的内存地址,即data跟list是同一个对象,list改变的话data也跟着改变);应该这么做:

data.clear();//要先清空data中的数据,避免把list中的数据重复放入data中。

data.addAll(list);//这样做,list中的数据就放入到data中,之后list在后台线程中改变,但data不会改变,这时,你再

SimpleAdapter adapter = new SimpleAdapter(LocalActivity.this,data,R.layout.local_music_list,new String[] {"local_name","local_size"}, new int[]{R.id.local_name,R.id.local_size});

listView与data绑定,就不会发生上述异常了!

更多相关文章

  1. android动态显示图片
  2. bitmap 压缩 compress
  3. android图片异步加载到本地
  4. Android中常用工具类
  5. 蓝牙后台长连接 服务
  6. 47 Android(安卓)fragment 接口回调
  7. 84 Android(安卓)Hnadler 封装下载图片工具类
  8. Android异步加载图片详解之方式二(3)
  9. android:打开第三方数据库

随机推荐

  1. C语言数组添加和删除元素的实现
  2. 面向小白visual studio 2019 添加第三方
  3. jsp登录页面的简单实例 雏形
  4. jsp登录页面的简单实例 雏形
  5. Yii 框架使用Gii生成代码操作示例
  6. Yii 框架入口脚本示例分析
  7. jsp登录页面的简单实例 雏形
  8. 光影如何绘画?漫画人物脸部光影画法
  9. 模态框的实例演示
  10. jsp中自定义Taglib详解