惊现RecyclerView内部Bug???别急,我们慢慢解决它~
写在前面
这也是久违的一整个月没有写 Blog,也是由于近期给妹纸找工作,各种坑蒙拐骗,然而都没卵用。额,广大朋友们,成都需要软件测试、线上运维、产品助理的伙伴,赶紧私聊我了。这妹纸,学习能力挺好,资质也不错,专业成绩总体排名年级第二,保送研究生(近期已决定放弃),心动不如行动,晚了就没机会了,赶紧私信我吧。
惊现 RecyclerView 内部 bug?
扯淡就不扯淡了,咱们还是说说这个早就可能被写烂吐槽的 RecyclerView 的 bug 吧。
不知道你们遇见没有,在 RecyclerView 被推的如火如荼的时候,你喜欢它,你默默用它,甚至对它的健壮性爱不释手。你觉得,这玩意儿都出来这么久了,一定没问题。额,没毛病。然而,在某一次快速滑动中,Boom,崩溃了!瞬间打脸。
查看 Log 得到下面的玩意儿。
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 157(offset:157).state:588 at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3300) at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3258) at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1803) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1302) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1265) at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1093) at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:956) at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:2715) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725) at android.view.Choreographer.doCallbacks(Choreographer.java:555) at android.view.Choreographer.doFrame(Choreographer.java:524) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711) at android.os.Handler.handleCallback(Handler.java:615) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4921) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794) at dalvik.system.NativeStart.main(Native Method)
杂一看像是数组越界?NO NO NO,这日志看上去根本就跟我们代码无关呀。多番 Google 发现,这貌似是 Google 程序员的锅?内部 bug?这TM官方的问题,关你何事?要不咱们不用 RecyclerView 了吧?
你是一个优秀的程序猿,不应该总是逃避问题,而应该思考如何去解决它。不过这说明了一个问题,人非圣贤孰能无过,连 Google 程序员那么牛逼的存在都会出问题,我们是不是......嘿嘿。
这玩意儿崩溃的原因比较清楚,就是如果绑定的集合List中的数据和 RecycerView 的数据不一致的时候,调用更新方法的时候会复现。
怎么解决?
有人这么说,造成崩溃的原因极有可能是当 clear 了之后,迅速上滑,但由于新数据还没来,导致 RecyclerView 需要更新加载下面的 Item 的时候,找不到数据源,导致了崩溃的发生。
所以,既然如此,一定可以通过让 Clear 的时候,禁止 RecyclerView 的滑动来解决它。代码如下:
private boolean mIsRefreshing=false; mRecyclerView.setOnTouchListener( new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (mIsRefreshing) { return true; } else { return false; } } } ); //当刷新时设置 //mIsRefreshing=true; //刷新完毕后还原为false //mIsRefreshing=false;
其它人的意见
人,想法,总是千奇百怪。
造成崩溃的原因其实很明显,如果你更新集合 List 后,调用 RVAdapter 的 notifyXXXX 方法时,adapter 的更新预期接口和实际集合更新结果不同,就会出现这个异常!不信你可以随便模拟这个情况的发生。
所以有人就得到了这样的结论:
RVAdapter 的 notifyDataSetChanged 方法执行后,在一定时间内,如果你更新了你的集合(无论是否在主线程更新集合),那么这个更新会实时反应到控件上,也就是说你的控件显示也会更新。
调用诸如 notifyItemRangeInserted 这样的方法之前,考虑清楚你的集合到底更新成什么样了!要注意参考结论1,结论1会影响你的判断。
解决该问题的正确姿势?
显然,上面的方法都不太好用,继续研究发现,直接采用下面的方法可以很好的解决。
经过多番研究发现,直接像下面这样,可以完美解决我们的问题。
1、复写 LinearLayoutManager
package com.zxedu.ischool.common; import android.content.Context; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; /** * Author: nanchen * Email: liushilin520@foxmail.com * Date: 2017-05-19 15:56 */ public class WrapContentLinearLayoutManager extends LinearLayoutManager { public WrapContentLinearLayoutManager(Context context) { super(context); } public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { try { super.onLayoutChildren(recycler, state); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } } }
对,没错,直接更换LayoutManaer就OK了
// mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); // 解决RecyclerView可能出现的holder数组越界Bug mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
写在最后
请别问我为什么这样就能解决?我会大声告诉你,我也不知道!
我能怎么办,我也很无奈~
做不完的开源,写不完的矫情。欢迎扫描下方二维码或者公众号搜索「nanchen」关注我的微信公众号,目前多运营 Android ,尽自己所能为你提升。如果你喜欢,为我点赞分享吧~
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Kotlin 极简教程 目录
目录 第0章 JVM语言家族 编程语言简史 程序的三种执行方式 编译执行 解释执行 第1章 Kotlin简介 第2章 快速开始:HelloWorld 第3章 kotlinc编译过程分析 第4章 类型系统 第5章 语法基础 第6章 面向对象编程(OOP) 第7章 函数式编程(FP) 第8章 Kotlin与Java混合调用 第9章 集成Spring Boot开发 第10章 Kotlin的多线程:协程(Coroutines) 第11章 使用Kotlin实现DSL 第12章 使用Kotlin开发JavaScript代码 第13章 使用Kotlin开发Android程序 第14章 使用Kotlin Native开发原生应用 《Kotlin极简教程》正式上架: 点击这里 > 去京东商城购买阅读 点击这里 > 去天猫商城购买阅读
- 下一篇
Zxing 的集成 ---- Maven 对应 Gradle 的写法
刚刚想耍耍二维码,想到了zxing和zbar,又想到zxing是Google老爹的,想想就算了吧,虽然zbar快但是识别错误率也高不少.随手Google了下*zxing 集成*好像都是说什么拷贝项目到自己的工程中,我不信Gradle集成这么方便了为何不用.于是我来到zxing的 Github 主页https://github.com/zxing/zxing,在README的引导下来到Get Start页面,里面有如下说明: Maven core/, javase/, android-integration and zxingorg can be used directly in a Maven-based project without any download or installation. Instead, add as dependencies from groupID com.google.zxing artifactIDs core, javase, android-integration or zxingorg: <dependencies> ... <...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS关闭SELinux安全模块
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 设置Eclipse缩进为4个空格,增强代码规范
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路