【知識整理】RecyclerView内部Bug???焦らないでゆっくり解決しよう

12716 ワード

一、前に書く
       これも久しぶりに一ヶ月Blogを書いていないので、最近妹紙に仕事を探して、いろいろなことを誘拐して、しかし卵がありません.ええ、多くの友达、成都はソフトウェアテスト、オンライン運営、製品アシスタントのパートナーが必要で、急いで私の話をしました.この妹紙、学習能力はとても良くて、資質も悪くなくて、専門の成績は全体的に学年の第2位で、大学院生を推薦して(最近すでに放棄することを決定しました)、心が動くより行動して、遅くなったらチャンスがなくて、急いで私を信じましょう.
この記事は、次のように同期して公開されます.
      簡単な本:http://www.jianshu.com/p/d520e6559433
      CSDN:http://blog.csdn.net/nanchen_lsl/article/details/72829093
二、RecyclerViewの内部バグに驚いた?
      いい加減にして、とっくにツッコミを書かれている可能性のあるRecyclerViewのバグについて話しましょう.
      あなたたちが出会ったかどうか分からないが、RecyclerViewが押されたとき、あなたはそれが好きで、あなたは黙ってそれを使って、甚だしきに至ってはその丈夫さ(艹、このようにしても性、愛)に手を放さない.あなたは、これがこんなに長い間出てきたので、きっと大丈夫だと思います.ええ、大丈夫です.しかし、ある高速スライドの中で、Boomは、崩壊しました!一瞬にして顔を殴る.
     ログを見て次のものを手に入れます.
 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プログラマーの鍋のようだ.内部バグ?このTM公式の問題は、あなたと何の関係がありますか?RecyclerViewは使わないでしょう?
    あなたは優秀なプログラム猿で、いつも問題を避けるのではなく、どのように解決するかを考えるべきです.しかし、これは一つの問題を説明しています.人が聖賢でなければ、誰が過ちを犯すことができないのか、Googleプログラマーのような牛の存在さえ問題になります.私たちは......へへへ.
    このクラッシュの原因は,バインドされた集合リストのデータとRecycerViewのデータが一致しない場合,更新メソッドを呼び出すと再現されることが明らかである.
三、どうやって解決しますか.
    クラッシュの原因はclear後、すばやくスライドする可能性が高いと言われていますが、新しいデータが来ていないため、RecyclerViewが次のItemを更新してロードする必要がある場合、データソースが見つからずクラッシュが発生します.
    だから、そうである以上、クリアしたときに、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;

四、他の人の意見
      人、考え、いつも奇妙だ.
      クラッシュの原因は明らかですが、集合リストを更新した後、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: nanchen
10  * Email: [email protected]
11  * Date: 2017-05-19  15:56
12  */
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     @Override
28     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    Bug
3         mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));

六、最後に書く
     どうしてこれで解決できるのか聞かないでください.私は大声であなたに教えて、私も知りません!
     どうすればいいのか、私も仕方がない.