最近發現應用在線上報了一個bug,乍一看,定位不到我們的代碼問題,但是就是crash了,自己也是一臉懵逼,後來經過網上資料查找,這個問題不是我們的代碼問題,是Recyclerview內部的bug,你敢信!!!,Google的東西都有bug..............
話不多說,看下下面的報錯:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 10(offset:0).state:11
at com.ushareit.playit.qr.a(SourceFile:4503)
at com.ushareit.playit.qr.c(SourceFile:4461)
at com.ushareit.playit.pq.a(SourceFile:1962)
at android.support.v7.widget.GridLayoutManager.a(SourceFile:438)
at android.support.v7.widget.LinearLayoutManager.a(SourceFile:1334)
at android.support.v7.widget.LinearLayoutManager.c(SourceFile:563)
at android.support.v7.widget.GridLayoutManager.c(SourceFile:171)
at android.support.v7.widget.RecyclerView.k(SourceFile:2801)
at android.support.v7.widget.RecyclerView.onLayout(SourceFile:3145)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.support.v4.view.ViewPager.onLayout(SourceFile:1627)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1160)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.support.v4.widget.DrawerLayout.onLayout(SourceFile:1043)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1888)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1742)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1651)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.widget.FrameLayout.layoutChildren(FrameLayout.java:515)
at android.widget.FrameLayout.onLayout(FrameLayout.java:450)
at android.view.View.layout(View.java:15125)
at android.view.ViewGroup.layout(ViewGroup.java:4862)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2323)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2029)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1192)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6231)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:788)
at android.view.Choreographer.doCallbacks(Choreographer.java:591)
at android.view.Choreographer.doFrame(Choreographer.java:560)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:774)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5292)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)
出現這個問題的原因和重現的方法是:使用RecyclerView加官方下拉刷新的時候,如果綁定的List對象在更新數據之前進行了clear,而這時用戶緊接着迅速上滑 RV,就會造成崩潰,而且異常不會報到你的代碼上,屬於RV內部錯誤。初次猜測是,當你clear了list之後,這時迅速上滑,而新數據還沒到來,導致Recyclerview要更新加載下面的Item時候,找不到數據源了,造成crash.
但明顯,更新數據之前clear list是挺常見的做法,你不可能祈禱用戶這時候乖乖不動等待新數據加載完,所以根本就是不合理的。
查找資料,有些說的解決方法是,就是在刷新,Recyclerview clear的同時讓Recyclerview不能滑動,這樣的解決辦法也是可以的,可以避免錯誤的發生,但是我總感覺這樣的會影響用戶的體驗,該解決辦法的代碼如下:
mRecyclerView.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mIsRefreshing) {
return true;
} else {
return false;
}
}
}
);
還有一種解決辦法就是,我們寫一個WrapContentLinearLayoutManager去繼承LinearLayoutManager,在出現問題的時候我們catch了,這樣的處理方法我覺得還是可以的,具體實現如下:
public class WrapContentLinearLayoutManager extends LinearLayoutManager {
public WrapContentLinearLayoutManager(Context context) {
super(context);
}
public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
mRecyclerView.setLayoutManager(new WrapContentLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));