记录一次IllegalStateException异常的解决过程
来源:互联网 发布:中国人口流动数据 编辑:程序博客网 时间:2024/04/29 09:17
异常内容:
07-16 20:21:37.411: ERROR/AndroidRuntime(324): 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. [in ListView(-1, class com.ringcentral.android.utils.ui.widget.PullToRefresh$7) with Adapter(class android.widget.HeaderViewListAdapter)]07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.widget.ListView.layoutChildren(ListView.java:1492)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.widget.AbsListView.onTouchModeChanged(AbsListView.java:1960)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.view.ViewTreeObserver.dispatchOnTouchModeChanged(ViewTreeObserver.java:591)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.view.ViewRoot.ensureTouchModeLocally(ViewRoot.java:2021)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.view.ViewRoot.ensureTouchMode(ViewRoot.java:2005)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.view.ViewRoot.handleMessage(ViewRoot.java:1774)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.os.Handler.dispatchMessage(Handler.java:99)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.os.Looper.loop(Looper.java:123)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at android.app.ActivityThread.main(ActivityThread.java:4627)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at java.lang.reflect.Method.invokeNative(Native Method)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at java.lang.reflect.Method.invoke(Method.java:521)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)07-16 20:21:37.411: ERROR/AndroidRuntime(324): at dalvik.system.NativeStart.main(Native Method)
怪就怪在报错的这个控件我的界面根本没用,而错误触发的时机却是在我的见面切换焦点所致~!(在模拟器上按上下左右键,就报错了。)。。。实在是无语。开始不想看源码,扭捏了一阵(主要是这错误太奇怪,不知从哪看起)。在界面里的相关控件中乱去设置setFocusable()。弄了一天,没有任何进展。哎,还是硬着头皮看源码吧。
根据异常堆栈信息,错误是报在ListView.layoutChildren()里的.
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. [in ListView(" + getId() + ", " + getClass() + ") with Adapter(" + mAdapter.getClass() + ")]"); }
mItemCount就是ListView列表项的个数。是因为与adapter提供的count不一致,所以报错。
报错的信息是没错的,是我们工程中一个下拉刷新的控件写得有问题。由于问题不具有普遍性。我就着重讲一下这次研究源码所得到的收获.
ListView:
public void setAdapter(ListAdapter adapter) { if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } resetList(); mRecycler.clear(); if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; } mOldSelectedPosition = INVALID_POSITION; mOldSelectedRowId = INVALID_ROW_ID; // AbsListView#setAdapter will update choice mode states. super.setAdapter(adapter); if (mAdapter != null) { mAreAllItemsSelectable = mAdapter.areAllItemsEnabled(); mOldItemCount = mItemCount; mItemCount = mAdapter.getCount(); checkFocus(); mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); mRecycler.setViewTypeCount(mAdapter.getViewTypeCount()); int position; if (mStackFromBottom) { position = lookForSelectablePosition(mItemCount - 1, false); } else { position = lookForSelectablePosition(0, true); } setSelectedPositionInt(position); setNextSelectedPositionInt(position); if (mItemCount == 0) { // Nothing selected checkSelectionChanged(); } } else { mAreAllItemsSelectable = true; checkFocus(); // Nothing selected checkSelectionChanged(); } requestLayout(); }由于ListView需要先 addHeader再setAdapter, 而不能先setAdapter再addHeader。是因为下面这几行代码
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) { mAdapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); } else { mAdapter = adapter; }
原来ListView有header的时候,它会创建一个HeaderViewListAdapter的实例并将你的adapter作为参数传进去。因此,如果先设置了adapter,再想添加header,就无法添加了。
至于这里这个bug产生的原因,确切的操作步骤是先使用软键盘转换焦点,再用手指直接点击屏幕。这时Android就会产生一个事件表示TouchModeChanged,由于我们的UI结构是有一个父的Activity,然后有几个子界面是作为像Tab页那样显示在父界面中的,因此这几个子界面都会接到父界面派发的这个事件。这就解释为什么当前没有显示的界面也能收到这个消息并产生一系列动作。
当然,最主要的原因,还是这个下拉刷新的控件写得有问题(这个网上有现成的,不过我们不能用开源代码,所以是公司内部实现的),哪里有问题呢
listView = new ListView(context, attrs) { @Override public BaseAdapter getAdapter() { if (adapter != null) { return adapter.getInnerAdapter(); } else { return null; } } };
返回的是界面中实现的Adapter,为什么说问题在此?因此有header的ListView实际上用的是HeaderViewListAdapter,这样让ListView情何以堪啊。而且因为HeaderViewListAdapter会重写getCount等函数,会自动处理header和footer的数量,
- 记录一次IllegalStateException异常的解决过程
- 记录一次git解决冲突的过程
- 记一次rsyslog日志记录失败的解决过程
- 记录一次自定义参数绑定错误问题的解决过程
- IllegalStateException异常解决
- 一次线上GC故障解决过程记录
- 记录一次impdp的过程
- java.lang.IllegalStateException异常解决
- java.lang.IllegalStateException异常解决
- java.lang.IllegalStateException异常解决
- 完美解决 ListView偶尔爆出的异常:java.lang.IllegalStateException
- 解决使用MediaPlayer开发时抛IllegalStateException异常的办法
- 【记录】一次网站异常的处理
- 记一次c#调matlab时初始化异常的解决过程
- 记录一次Linux操作系统最大文件数限制的解决过程
- 【开卷有益】记录一次高并发下的死锁解决思考过程
- 记录一次.net项目的破解过程
- 记录一次软件Bug发生的过程
- Scrapy-CrawlSpider爬虫组件
- LINUX下USB1.1设备学习小记(5)_uhci与设备(1)
- Objective-C中的枚举类型
- zoj1119--双连通--寻找关节点---计算子网数
- poj3352--旅游岛修路--双连通--无向图邻接表的容量是边数量的2倍
- 记录一次IllegalStateException异常的解决过程
- hbase基本概念和hbase shell常用命令用法
- poj1236--强连通--tarjan--补强连通--最优分发
- MantisBT的邮件配置
- C#事件处理程序的写法
- I2C之知(二)--I2C总线SDA\SCL以及开始终止条件
- 判别ios设备的类型
- HDU 2063 过山车(二分图最大匹配问题)
- 如何更改SQL Server2008身份验证模式