转载请注明出处:
http://blog.csdn.net/user11223344abc?viewmode=contents
出自【蛟-blog】
1.吐槽:
本文为解决xRecyclerView的一个崩溃bug时候的问题。
异常信息:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 6(offset:6).
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3300)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:3258)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1803)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1302)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1265)
at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1093)
at android.support.v7.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:956)
at android.support.v7.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:2715)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
at android.view.Choreographer.doCallbacks(Choreographer.java:555)
at android.view.Choreographer.doFrame(Choreographer.java:524)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1027)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:794)
at dalvik.system.NativeStart.main(Native Method)
针对这异常,网上大概三套路:
- 上拉时,禁止滑动
private boolean mIsRefreshing=false;
mRecyclerView.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mIsRefreshing) {
return true;
} else {
return false;
}
}
}
);
//当刷新时设置
//mIsRefreshing=true;
//刷新完毕后还原为false
//mIsRefreshing=false;
- 数据源,删除,增加时,notify同步,bla..bla..bla..
主要针对Adapter内俩方法的封装:
public void addAll(boolean isFirstPage,List<ShopOrderListBean.DataBean> cells) {
// if (cells == null /*|| cells.size() == 0*/) {
// return;
// }
mDatas.addAll(mDatas.size(), cells);
if(isFirstPage){
notifyDataSetChanged();
}else {
notifyItemRangeChanged(mDatas.size(), mDatas.size() + cells.size());
}
}
public void clearDatas() {
if (null != mDatas) {
mDatas.clear();
}
notifyDataSetChanged();
}
- WrapLayoutManager
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));
对,其实他们说的都对,不过这是基于标准的RecyclerView角度的,本文讨论的是XRecyclerView的bug。
2.进入正题:天坑,XRecyclerView
我说说我解决问题的思路:
我在onloadmore内打了日志,比如我9条数据(实际上订单是一次请求10条),
当我滑动到第4条 或者第五条的时候,日志显示调了onloadmore,一onloadMore ,数据源发生改变(一般是在下一波数据长度为0的时候就会崩)。
按照常理来说,我9条数据拿到了,起码也要到了第九条的时候才会调onloadmore
那么提前调用onloadmore肯定是不对的,肯定是XRecyclerView源码哪儿有问题,我就去github上看了下,发现了这么一条issue,在此感谢那个回复这个issue的哥们。
https://github.com/jianghejie/XRecyclerView/issues/243
基于这条issue,我copy了xrecyclerView新建了一个类,NerverCrashXRecyclerView,这个累里边就改了一个变量,其他啥都没动。
就是在第255行修改如下:
if (layoutManager.getChildCount() > 0
&& lastVisibleItemPosition >= mWrapAdapter.getItemCount() - 1 && !isNoMore && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
至此问题才算真正得到解决。
3.附件
package com.sound.haolei.widget.XRecylerView;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import java.util.ArrayList;
import java.util.List;
import static com.sound.haolei.widget.XRecylerView.BaseRefreshHeader.STATE_REFRESHING;
public class NeverCarshXRecyclerView extends RecyclerView
{
private boolean isLoadingData = false;
private boolean isNoMore = false;
private int mRefreshProgressStyle = ProgressStyle.SysProgress;
private int mLoadingMoreProgressStyle = ProgressStyle.SysProgress;
private ArrayList<View> mHeaderViews = new ArrayList<>();
private WrapAdapter mWrapAdapter;
private float mLastY = -1;
private static final float DRAG_RATE = 3;
private LoadingListener mLoadingListener;
private ArrowRefreshHeader mRefreshHeader;
private boolean pullRefreshEnabled = true;
private boolean loadingMoreEnabled = true