贴出源代码:

android.widget.ListView

...

if(mItemCount == 0){
resetList();
invokeOnItemScrollListener();
return;
}else if(mItemCount != mAdapter.getCount()){
throw new 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. "
+"Make sure your adapter calls notifyDataSetChanged() when its content changes. "
+"[in ListView(" +getId() +"", + getClass + ") with Adapter(" + mAdapter.getClass+ ")]");
}

...

今天看见这个异常百思不得其解,幸好在论坛上看见一位牛人的解析,瞬间明了。

原文分析:

普通情况下。上述异常一般发生在我们启动一个后台线程载入数据,同一时候在主线程(即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条了。就是这个冲突导致了上述的异常!!!发生在else
if()推断语句处

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

在 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绑定,就不会发生上述异常了!

总结来说。即创建一个缓存变量。存储的值是第一次查询得到数据 ,后台线程继续查询出来的数据不再使用。如此就保证了显示数据时不会报出异常。

ListView IllegalStateException的更多相关文章

  1. 关于viewpager 里嵌套 listview 同时实现翻页功能的“java.lang.IllegalStateException: The specified child..."异常处理

    这几天做项目用到了ViewPager,因为它可以实现左右划动多个页面的效果,然后 再每个页面里使用ListView,运行时总是出现”PagerAdapter java.lang.IllegalStat ...

  2. 【转】解决java.lang.IllegalStateException: The content of the adapter has changed but ListView...的问题

    原文网址:http://blog.csdn.net/ueryueryuery/article/details/20607845 我写了一个Dialog,Dialog中有一个ListView,想要点Li ...

  3. java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification

    ListView UI重绘时触发layoutChildren, 此时会校验listView的mItemCount与其Adapter.getCount是否相同,不同报错. ListView.layout ...

  4. java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called.

    分析:android 4.2.X及以下的版本,addHeaderView必须在setAdapter之前,否则会抛出IllegalStateException. android 4.2.X(API 17 ...

  5. 深入理解使用ListView时ArrayAdapter、SimpleAdapter、BaseAdapter的原理

    在使用ListView的时候,我们传给setAdapter方法的Adapter通常是ArrayAdapter.SimpleAdapter.BaseAdapter,但是这几个Adapter内部究竟是什么 ...

  6. android开发中难免遇到listview刷新数据出现异常

    异常:java.lang.IllegalStateException: The content of the adapter has changed but ListView did not rece ...

  7. Android中ListView的各种显示效果

    在android应用开发中,ListView是使用频率非常高的一个组件,基本上稍微复杂点的布局都会用到它,利用它可以让你的界面美观,有层次 .ListView可以用来作为数据显示的容器,也可以作为界面 ...

  8. Android ListView 进阶学习

    1.使用ListView展示数据结构为二维数组的数据 当我们遇到数据结构是二维数组的需求的时候,我们会首先想到ListView,但是要想实现二维数组,会想到ListView里面嵌套ListView,但 ...

  9. ListView:The content of the adapter has changed but ListView did not receive a notification终极解决方法

    使用ListView时遇到如下的异常信息: 10-26 18:30:45.085: E/AndroidRuntime(7323): java.lang.IllegalStateException: T ...

随机推荐

  1. [计算机基础]URI与URL

    URI : uniform resource identifier统一资源标示符用于指定Web资源的字符串,它定义了Web资源中的各个不同的部分.ex:http://example.org/absol ...

  2. must return an Iterable of arrays.(junit4)

    java.lang.Exception: TestIterator.init() must return an Iterable of arrays. at org.junit.runners.Par ...

  3. 基于raw os 的事件触发系统

    Raw os的事件触发系统有以下特点: 1 基于UML的状态机理念设计,实现了有限状态机(fsm)以及层次状态机(HSM). 2 实现了活动对象(ACTIVE OBJECT)的特性,一个活动对象包含了 ...

  4. ios html5 设定PhoneGap开发环境

    怎么样IOS平台搭建PhoneGap开发环境(PhoneGap2.5) (2013-03-13 14:44:51) 标签: c=blog&q=it&by=tag" targe ...

  5. 高级Bash脚本编程指南(27):文本处理命令(三)

    高级Bash脚本编程指南(27):文本处理命令(三) 成于坚持,败于止步 处理文本和文本文件的命令 tr 字符转换过滤器. 必须使用引用或中括号, 这样做才是合理的. 引用可以阻止shell重新解释出 ...

  6. QT断点续传(原理:需要在HTTP请求的header中添加Rang节,告诉服务器从文件的那个位置开始传输.格式为bytes 开始传输的位置)

    //功能:    根据一个URL地址将数据保存到指定路径下,支持断点续传//参数:    url            --需要访问的URL地址//         SavePath       -- ...

  7. 推动Common Lisp的实际应用

    推动Common Lisp的实际应用 推动Common Lisp的实际应用

  8. C# Http以文件的形式上传文件

    以下的是上传的方法: // <summary> /// 将本地文件上传到指定的服务器(HttpWebRequest方法) /// </summary> /// <para ...

  9. linux文件夹介绍

    (1)documentation 这个文件夹下没有内核代码,仅仅有一套实用的文档,但这些文档的质量不一.比如内核文档的文件系统,在该文件夹下有相当优秀并且相当完整的文档:而另外一部分内核,比如进程调度 ...

  10. C#整理

    输入输出--数据类型--变量与常量--运算符表达式--语句(顺序.分支.循环)--数组--函数--结构体一.输入与输出.Console.ReadLine();Console.WriteLine();C ...