【转】关于Adapter的The content of the adapter has changed问题分析 关于Adapter的The content of the adapter has changed问题分析

原文网址:http://www.cnblogs.com/monodin/p/3874147.html

1、问题描述

 1 07-28 17:22:02.162: E/AndroidRuntime(16779): 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. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131034604, class android.widget.ListView) with Adapter(class com.nodin.sarah.HeartListAdapter)]
 2
 3 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.ListView.layoutChildren(ListView.java:1555)
 4
 5 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.AbsListView.onLayout(AbsListView.java:2091)
 6
 7 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
 8
 9 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
10
11 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1055)
12
13 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
14
15 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
16
17 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
18
19 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
20
21 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
22
23 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
24
25 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1589)
26
27 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
28
29 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
30
31 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1055)
32
33 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
34
35 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
36
37 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
38
39 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
40
41 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
42
43 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
44
45 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1671)
46
47 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1525)
48
49 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.LinearLayout.onLayout(LinearLayout.java:1434)
50
51 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
52
53 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
54
55 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
56
57 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
58
59 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.View.layout(View.java:14785)
60
61 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewGroup.layout(ViewGroup.java:4631)
62
63 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1985)
64
65 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1742)
66
67 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:998)
68
69 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5582)
70
71 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
72
73 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.Choreographer.doCallbacks(Choreographer.java:562)
74
75 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.Choreographer.doFrame(Choreographer.java:532)
76
77 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
78
79 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.os.Handler.handleCallback(Handler.java:733)
80
81 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.os.Handler.dispatchMessage(Handler.java:95)
82
83 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.os.Looper.loop(Looper.java:137)
84
85 07-28 17:22:02.162: E/AndroidRuntime(16779):   at android.app.ActivityThread.main(ActivityThread.java:4998)
86
87 07-28 17:22:02.162: E/AndroidRuntime(16779):   at java.lang.reflect.Method.invokeNative(Native Method)
88
89 07-28 17:22:02.162: E/AndroidRuntime(16779):   at java.lang.reflect.Method.invoke(Method.java:515)
90
91 07-28 17:22:02.162: E/AndroidRuntime(16779):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
92
93 07-28 17:22:02.162: E/AndroidRuntime(16779):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
94
95 07-28 17:22:02.162: E/AndroidRuntime(16779):   at dalvik.system.NativeStart.main(Native Method)
96
97 07-28 17:22:02.162: W/ActivityManager(588):   Force finishing activity  

2、复现场景

使用ListView和Adapter实现动态增删数据列表功能,初始化数据分为两部分:本地和网络。所以在Adapter的数据初始化的时候,先讲本地数据添加到了容器内。同时发起网络请求,等加载完毕后追加到容器内。

问题出现在:当网络请求完毕后追加数据的时候,抛出上述异常。

3、原因分析

Exception解读:

Adapter的数据内容已经改变,但是ListView却未接收到通知。要确保不在后台线程中修改Adapter的数据内容,而要在UI Thread中修改。确保Adapter的数据内容改变时一定要调用notifyDataSetChanged()方法。

且不管Exception内容,先查询Android源码看看该Exception是从哪里抛出来的。

在ListView的layoutChildren()方法里有如下一段方法:

 1 // Handle the empty set by removing all views that are visible
 2 // and calling it a day
 3 if (mItemCount == 0) {
 4     resetList();
 5     invokeOnItemScrollListener();
 6     return;
 7 } else if (mItemCount != mAdapter.getCount()) {
 8     throw new IllegalStateException("The content of the adapter has changed but "
 9             + "ListView did not receive a notification. Make sure the content of "
10             + "your adapter is not modified from a background thread, but only "
11             + "from the UI thread. [in ListView(" + getId() + ", " + getClass()
12             + ") with Adapter(" + mAdapter.getClass() + ")]");
13 }

亦即,当ListView缓存的数据Count和ListView中Adapter.getCount()不等时,会抛出该异常。

结合开头的异常解读,可以断定肯定是Adapter数据动态更新的问题。仔细检查了自己的代码:

当网络请求完毕后,直接在网络线程(非UI线程)里调用了在Adapter中新增的自定义方法addData(List)更新数据,而addData(List)方法内更新换完数据后,通过Handler发送Message的策略调用Adapter的notifyDataSetChanged()方法通知更新。

这么一来,并不能保证Adapter的数据更新时,立马调用notifyDataSetChanged()通知ListView,这两个线程之间的时间差引起的数据不同步,导致ListView的layoutChildren()中访问Adapter的getCount()方法时,Adapter内已经是最新数据源,而ListView内的缓存数据Count仍是旧数据的Count,该问题最终原因终于浮出水面。

4、解决方案

在本例中,解决方案是:把addData(List)方法内更新数据的代码挪出来,和notifyDataSetChanged()方法一同放在Handler里,保证数据更新时及时通知ListView。

为了尽量避免该问题,以后编程尽量从如下几个方面检查自己的代码:

  • 确保Adapter的数据更新后一定要调用notifyDataSetChanged()方法通知ListView
  • 数据更新和notifyDataSetChanged()放在UI线程内,且必须同步顺序执行,不可异步
  • 仔细检查确认getCount()方法返回值是否正确
时间: 2024-08-27 00:43:28

【转】关于Adapter的The content of the adapter has changed问题分析 关于Adapter的The content of the adapter has changed问题分析的相关文章

I have Flash Player installed, but I am unable to view Flash content in Chromium. How do I enable Flash Player to view this content?

I have Flash Player installed, but I am unable to view Flash content in Chromium. How do I enable Flash Player to view this content? If you have installed Flash Player for Chromium, but cannot see Flash-based content, you may have disabled Flash Play

包含了重复的“Content”项。.NET SDK 默认包含你项目目录中的“Content”项。可从项目文件中删除这些项;如果希望将其显式包含在项目文件中,可将“EnableDefaultContentItems”属性设置为“false”

从.netcore 1.1 升级到2.0时遇到该问题. 参考http://www.cnblogs.com/xishuai/p/visual-studio-for-mac.html 根据提示可知(我是看不明白),经过文章中提示,将csproj文件中ItemGroup节点下,Content 节点全部删除就ok了. <ItemGroup> <Content Include="Properties\launchSettings.json" /> </ItemGro

Android开发- 数据库和Content Provider

SQLiteOpenHelper SQLiteOpenHelper是一个抽象类,用来实现创建.打开和升级数据库的最佳实践模式. private static class HoardDBOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "myDatabase.db"; private static final String DATABASE_TABLE = "Gol

VMware Network Adapter VMnet1和VMnet8 被归入[未识别的网络-公用网络]的解决方法(转录的)

系统: Windows7 x64 虚拟软件: VMware Workstation 7.1.3 情况:VMware Network Adapter VMnet1和VMnet8 被防火墙认定为[未识别的网络-公用网络],阻隔,无法使用端口映射,虚拟机的80端口无法传入,数据包只能出不能入.且公用网络被限制不能修改为家庭或工作网络. 解决方法:参考VMware的知识库文章 [http://kb.vmware.com/selfservice/microsites/search.do?language=

dhroid - NetJSONAdapter 网络化的adapter

关于adapter 我想对于大家来说已经不陌生了,基本应用都会用的很多,不知道现在你是不是还是按一定的套路写很多代码去实现adapter我想大多数人还是写个adapter继承自baseadapter 实现getView方法(我想大家还会用网络流行的viewholder模式吧),如果数据来自网络用个网络访问工具访问数据,数据转换,然后add进adapter,如果有下拉刷新,加载更多代码会更多问题1.你在写很多重复代码2.数据管理不是那么容易3.网络缓存需要处理 如果你使用dhroid框架,这些问题

布局与控件(九)-ListView的Adapter们

第10节 ListView的Adapter 安卓系统为ListView设计了多种Adapter作为它的搭档.每种Adapter不仅为ListView提供数据内容,也会告诉ListView如何展示这些数据-规定好列表项的长相. 这些Adapter都是从Adapter类继承而来的,它们的关系如下: 这里我们选择性的介绍常见的2种Adapter-ArrayAdapter和SimpleAdapter. 10.1 ArrayAdapter ArrayAdapter是最简单的Adapter,我们在前面已经使

Android 学习心得(4)——Content Provider(内容提供者)

———————————————————————————————————————— |作者:wangkuifeng0118|地址:http://blog.csdn.net/wangkuifeng0118/article/details/7028953 ———————————————————————————————————————— Content Provider 属于Android应用程序的组件之一,作为应用程序之间唯一的共享数据的途径,Content Provider 主要的功能就是存储并检索

Android开发-API指南-Content Provider基础

Content Provider Basics 英文原文:http://developer.android.com/guide/topics/providers/content-provider-basics.html 采集日期:2015-01-07 在本文中 概述 访问 Provider Content URI 从 Content Provider 读取数据 申请读取权限 建立查询请求 显示查询结果 从查询结果中获取数据 Content Provider 相关权限 插入.修改.删除数据 插入数

Android应用程序组件Content Provider应用实例

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6950440 文简要介绍了Android应用程序组件Content Provider在应用程序间共享数据的原理,但是没有进一步研究它的实现.本文将实现两个应用程序,其中一个以Content Provider的形式来提供数据访问入口,另一个通过这个Content Provider来访问这些数据.本文的例子不仅可以为下文分析Content Provi

Dhroid框架笔记(DhNet、Adapter)

3.1.1 DhNet用于获取网络中的数据 DhNet net=new DhNet("路劲"); net.addParam("key", "参数").addParam("key2", "参数2"); net.doGet(new NetTask(this) { @Override public void doInUI(Response response, Integer transfer) {//处理返回结果