正文

回到顶部

一、写在前面

       这也是久违的一整个月没有写Blog,也是由于近期给妹纸找工作,各种坑蒙拐骗,然而都没卵用。额,广大朋友们,成都需要软件测试、线上运维、产品助理的伙伴,赶紧私聊我了。这妹纸,学习能力挺好,资质也不错,专业成绩总体排名年级第二,保送研究生(近期已决定放弃),心动不如行动,晚了就没机会了,赶紧私信我吧。

  该文章同步发布到:

      简书:http://www.jianshu.com/p/d520e6559433

      CSDN:http://blog.csdn.net/nanchen_lsl/article/details/72829093

回到顶部

二、惊现 RecyclerView 内部bug?

      扯淡就不扯淡了,咱们还是说说这个早就可能被写烂吐槽的RecyclerView的bug吧。

      不知道你们遇见没有,在RecyclerView被推的如火如荼的时候,你喜欢它,你默默用它,甚至对它的健壮性(艹,这样也算是性、爱)爱不释手。你觉得,这玩意儿都出来这么久了,一定没问题。额,没毛病。然而,在某一次快速滑动中,Boom,崩溃了!瞬间打脸。

     查看Log得到下面的玩意儿。

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 157(offset:157).state:588 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)

大学生就业培训,高中生培训,在职人员转行培训,企业团训

    杂一看像是数组越界?NO NO NO,这日志看上去根本就跟我们代码无关呀。多番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 //刷新完毕后还原为false17 //mIsRefreshing=false;

大学生就业培训,高中生培训,在职人员转行培训,企业团训

回到顶部

四、其它人的意见

      人,想法,总是千奇百怪。

      造成崩溃的原因其实很明显,如果你更新集合List后,调用RVAdapter的notifyXXXX方法时,adapter的更新预期接口和实际集合更新结果不同,就会出现这个异常!不信你可以随便模拟这个情况的发生。

      所以有人就得到了这样的结论:

      1、RVAdapter的notifyDataSetChanged方法执行后,在一定时间内,如果你更新了你的集合(无论是否在主线程更新集合),那么这个更新会实时反应到控件上,也就是说你的控件显示也会更新。

      2、调用诸如notifyItemRangeInserted这样的方法之前,考虑清楚你的集合到底更新成什么样了!要注意参考结论1,结论1会影响你的判断。

回到顶部

五、解决该问题的正确姿势?

     显然,上面的方法都不太好用,继续研究发现,直接采用下面的方法可以很好的解决。

     经过多番研究发现,直接像下面这样,可以完美解决我们的问题。

    1、复写LinearLayoutManager

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 package com.zxedu.ischool.common; 2  3 import android.content.Context; 4 import android.support.v7.widget.LinearLayoutManager; 5 import android.support.v7.widget.RecyclerView; 6 import android.util.AttributeSet; 7  8 /** 9  * Author: nanchen10  * Email: liushilin520@foxmail.com11  * Date: 2017-05-19  15:5612  */13 14 public class WrapContentLinearLayoutManager extends LinearLayoutManager {15     public WrapContentLinearLayoutManager(Context context) {16         super(context);17     }18 19     public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {20         super(context, orientation, reverseLayout);21     }22 23     public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {24         super(context, attrs, defStyleAttr, defStyleRes);25     }26 27     @Override28     public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {29         try {30             super.onLayoutChildren(recycler, state);31         } catch (IndexOutOfBoundsException e) {32             e.printStackTrace();33         }34     }35 }

大学生就业培训,高中生培训,在职人员转行培训,企业团训

       2、对,没错,直接更换LayoutManaer就OK了

1 //        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));2         // 解决RecyclerView可能出现的holder数组越界Bug3         mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));

回到顶部

六、写在最后

     请别问我为什么这样就能解决?我会大声告诉你,我也不知道!

     我能怎么办,我也很无奈~


作  者: 南 尘   大学生就业培训,高中生培训,在职人员转行培训,企业团训 
出  处: http://www.cnblogs.com/liushilin/ 
关于作者:专注于移动前端的项目开发。如有问题或建议,请多多赐教!欢迎加入Android交流群:118116509 
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 
声援博主:如果您觉得文章对您有帮助,可以点击文章下部推荐或侧边关注。您的鼓励是作者坚持原创和持续写作的最大动力! 

http://www.cnblogs.com/liushilin/p/6927612.html


延伸阅读

告别“老顽固”-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训告别“老顽固”