最近忙着赶项目进度,都不知道此次博客写点啥好了,前两天碰巧遇到一个奇怪的bug,项目中未发现与异常相关的类,因而去百度、谷歌搜索,发现这是一个早就可能被写烂吐槽的RecyclerView的bug.java
不知道大家碰见没有,在RecyclerView被推的如火如荼的时候,你喜欢它,你默默用它,青睐于它的健壮性。你以为,这玩意儿都出来这么久了,必定没问题。然而,在某一次快速滑动中,Boom,崩溃了!android
先来看下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的数据不一致的时候,调用更新方法的时候会复现。app
临时解决办法
ide
因此,既然如此,必定能够经过让Clear的时候,禁止RecyclerView的滑动来解决它。代码以下:oop
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;
人,想法,老是千奇百怪。this
形成崩溃的缘由其实很明显,若是你更新集合List后,调用RVAdapter的notifyXXXX方法时,adapter的更新预期接口和实际集合更新结果不一样,就会出现这个异常!不信你能够随便模拟这个状况的发生。spa
因此有人就获得了这样的结论:
一、RVAdapter的notifyDataSetChanged方法执行后,在必定时间内,若是你更新了你的集合(不管是否在主线程更新集合),那么这个更新会实时反应到控件上,也就是说你的控件显示也会更新。
二、调用诸如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;
写在最后
细心和耐心在编程之路显得尤其重要,只有抱着对bug0容忍的态度和决心,咱们才能越太高山,发现更高更远的天空