偶遇RecyclerView內部Bug

  • 寫在前面          

  最近忙着趕項目進度,都不知道此次博客寫點啥好了,前兩天碰巧遇到一個奇怪的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須要更新加載下面的Item的時候,找不到數據源,致使了崩潰的發生。

    因此,既然如此,必定能夠經過讓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容忍的態度和決心,咱們才能越太高山,發現更高更遠的天空

相關文章
相關標籤/搜索