首页 > 代码库 > 【原创】关于Adapter的The content of the adapter has changed问题分析
【原创】关于Adapter的The content of the adapter has changed问题分析
关于Adapter的The content of the adapter has changed问题分析
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数据动态更新的问题。仔细检查了自己的代码,发现在数据更新上有个问题:当网络请求完毕后,直接调用了Adapter的自定义方法addData(List)更新了数据,但是却遗漏了notifyDataSetChanged()方法(我勒个去。。。)。
如此,问题可以确定。加上notifyDataSetChanged(),问题搞定。
4、解决方案
具体原因比较复杂,但是肯定和Adapter的数据更新有关。尽量从如下几个方面检查自己的代码:
- 确保Adapter的数据更新后一定要调用notifyDataSetChanged()方法通知ListView
- 数据更新和notifyDataSetChanged()放在UI线程内,且必须同步顺序执行,不可异步
- 仔细检查确认getCount()方法返回值是否正确
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。