偶遇RecyclerView内部Bug

发表于:2018-11-15 13:26

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:你要    来源:博客园

#
Bug
分享:
  写在前面
  最近忙着赶项目进度,都不知道这次博客写点啥好了,前两天碰巧遇到一个奇怪的bug,项目中未发现与异常相关的类,于是去百度谷歌搜索,发现这是一个早就可能被写烂吐槽的RecyclerView的bug.
  透过现象看本质
  不知道你们遇见没有,在RecyclerView被推的如火如荼的时候,你喜欢它,你默默用它,青睐于它的健壮性。你觉得,这玩意儿都出来这么久了,一定没问题。然而,在某一次快速滑动中,Boom,崩溃了!
  先来看下logcat打的崩溃日志:
  1 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 6(offset:6).
  2         at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3300)
  3         at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3258)
  4         at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1803)
  5         at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1302)
  6         at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1265)
  7         at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1093)
  8         at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:956)
  9         at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:2715)
  10         at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
  11         at android.view.Choreographer.doCallbacks(Choreographer.java:555)
  12         at android.view.Choreographer.doFrame(Choreographer.java:524)
  13         at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
  14         at android.os.Handler.handleCallback(Handler.java:615)
  15         at android.os.Handler.dispatchMessage(Handler.java:92)
  16         at android.os.Looper.loop(Looper.java:137)
  17         at android.app.ActivityThread.main(ActivityThread.java:4921)
  18         at java.lang.reflect.Method.invokeNative(Native Method)
  19         at java.lang.reflect.Method.invoke(Method.java:511)
  20         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
  21         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
  22         at dalvik.system.NativeStart.main(Native Method)
  数组越界?这日志看上去根本就跟我们代码无关呀。多番Google发现,这貌似是Google程序员的锅?内部bug?这TM官方的问题,关你何事?要不不用RecyclerView了吧?
  你是一个优秀的程序猿,不应该总是逃避问题,而应该思考如何去解决它。不过这说明了一个问题,人非圣贤孰能无过,连Google程序员那么牛逼的存在都会出问题。
  崩溃的原因比较清楚,如果绑定的集合List中的数据和RecycerView的数据不一致的时候,调用更新方法的时候会复现。
  临时解决办法
  有人这么说,造成崩溃的原因极有可能是当clear了之后,迅速上滑,但由于新数据还没来,导致RecyclerView需要更新加载下面的Item的时候,找不到数据源,导致了崩溃的发生。
  所以,既然如此,一定可以通过让Clear的时候,禁止RecyclerView的滑动来解决它。代码如下:
  1 private boolean mIsRefreshing=false;
  2 mRecyclerView.setOnTouchListener(
  3     new View.OnTouchListener() {
  4       @Override
  5       public boolean onTouch(View v, MotionEvent event) {
  6         if (mIsRefreshing) {
  7           return true;
  8         } else {
  9           return false;
  10         }
  11       }
  12     }
  13 );
  14 //当刷新时设置
  15 //mIsRefreshing=true;
  16 //刷新完毕后还原为false
  17 //mIsRefreshing=false;
  别人怎么说
  人,想法,总是千奇百怪。
  造成崩溃的原因其实很明显,如果你更新集合List后,调用RVAdapter的notifyXXXX方法时,adapter的更新预期接口和实际集合更新结果不同,就会出现这个异常!不信你可以随便模拟这个情况的发生。
  所以有人就得到了这样的结论:
  1、RVAdapter的notifyDataSetChanged方法执行后,在一定时间内,如果你更新了你的集合(无论是否在主线程更新集合),那么这个更新会实时反应到控件上,也就是说你的控件显示也会更新。
  2、调用诸如notifyItemRangeInserted这样的方法之前,考虑清楚你的集合到底更新成什么样了!要注意参考结论1,结论1会影响你的判断。
  靠谱的解决办法
  显然,上面的方法都不太好用,继续研究发现,直接采用下面的方法可以很好的解决。
  经过多番研究发现,直接像下面这样,可以完美解决我们的问题。
  保证Adapter内的list和获取到的数据list不是同一个list就好.
  Class MyAdapter extends RecyclerView.Adapter{
  private List<Object>mList;
  ...
  public void notifySetListDataChanged(List<Object>list){
  this.mList = list;
  notifySetDataChanged();
  }
  }
  每次数据更新(只要有变动都认为是更新)都调用
  adapter.notifySetListDataChanged(list);这里的list是变动更新后的数据list;

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
精选软件测试好文,快来阅读吧~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号