2

我得到java.lang.IndexOutOfBoundsException: Inconsistency detectedRecyclerView,但只有當我似乎扔它。當我滾動足夠慢時,它不會對我造成影響。RecyclerView java.lang.IndexOutOfBoundsException:檢測到不一致。視圖持有人適配器位置無效。由於更改getItemCount()

我使用我的基座適配器許多其他的子類,但只有某些碰撞在我身上。任何想法爲什麼發生這種情況?

編輯

我想通了,因爲這取決於我的頁腳裝載視圖的狀態getItemCount()變化發生這種情況的原因。我相信當它發生變化並且正在滾動時,這會導致不一致。

我通過在getItemCount()中爲我的頁眉/頁腳加載視圖始終返回2個額外的項目來測試此項。而不是根據狀態動態計算計數。什麼是解決這個問題的好方法?

我的適配器

public abstract class BaseRecyclerAdapter<T> 
     extends RecyclerView.Adapter<RecyclerView.ViewHolder> 
     implements LoadingAndErrorViewHolder.LoadingViewHolderListener { 

    public static final int STATUS_HIDDEN = 0; 
    public static final int STATUS_LOADING = 1; 
    public static final int STATUS_ERROR = 2; 

    protected static final int TYPE_HEADER_LOADING = 0; 
    protected static final int TYPE_FOOTER_LOADING = 1; 
    protected static final int TYPE_NORMAL = 2; 

    private static final int POSITION_TYPE_HEADER_LOADING = 0; 

    private BaseRecyclerAdapterListener mBaseRecyclerAdapterListener; 
    private final List<T> mBackingList = new ArrayList<T>(); 
    private int mHeaderStatus = STATUS_HIDDEN; 
    private int mFooterStatus = STATUS_HIDDEN; 
    private final int mNumOfHeaderItems; 

    public interface BaseRecyclerAdapterListener { 
     void onErrorHeaderRetryClicked(); 
     void onErrorFooterRetryClicked(); 
    } 

    public BaseRecyclerAdapter() { 
     this(null); 
    } 

    public BaseRecyclerAdapter(BaseRecyclerAdapterListener listener) { 
     this(0, listener); 
    } 

    public BaseRecyclerAdapter(int numOfHeaderItems, BaseRecyclerAdapterListener listener) { 
     mNumOfHeaderItems = numOfHeaderItems; 
     mBaseRecyclerAdapterListener = listener; 
     setHasStableIds(true); 
    } 

    @Override 
    public long getItemId(int position) { 
     final T item = getItem(position); 
     if (item != null) { 
      return item.hashCode(); 
     } else { 
      return position; 
     } 
    } 

    @Override 
    public int getItemCount() { 
     int count = mBackingList.size(); 
     if (mHeaderStatus != STATUS_HIDDEN) { 
      count++; 
     } 
     if (mFooterStatus != STATUS_HIDDEN) { 
      count++; 
     } 
     return mNumOfHeaderItems + count; 
    } 

    @Override 
    public int getItemViewType(int position) { 
     final int headerAdjustment = mHeaderStatus != STATUS_HIDDEN ? 1 : 0; 
     if (position == 0 && mHeaderStatus != STATUS_HIDDEN) { 
      return TYPE_HEADER_LOADING; 
     } else if (position < mBackingList.size() + headerAdjustment + mNumOfHeaderItems) { 
      return TYPE_NORMAL; 
     } else { 
      return TYPE_FOOTER_LOADING; 
     } 
    } 

    @Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     final LayoutInflater inflater = LayoutInflater.from(parent.getContext()); 
     switch (viewType) { 
      case TYPE_HEADER_LOADING: { 
       return new LoadingAndErrorViewHolder(inflater.inflate(
         LoadingAndErrorViewHolder.LAYOUT_ID, parent, false), 
         LoadingAndErrorViewHolder.TYPE_HEADER, this); 
      } 
      case TYPE_FOOTER_LOADING: { 
       return new LoadingAndErrorViewHolder(inflater.inflate(
         LoadingAndErrorViewHolder.LAYOUT_ID, parent, false), 
         LoadingAndErrorViewHolder.TYPE_FOOTER, this); 
      } 
      default: { 
       return onCreateItemViewHolder(parent, viewType); 
      } 
     } 
    } 

    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
     final int viewType = getItemViewType(position); 
     switch (viewType) { 
      case TYPE_HEADER_LOADING: { 
       ((LoadingAndErrorViewHolder) holder).setStatus(mHeaderStatus); 
       break; 
      } 
      case TYPE_FOOTER_LOADING: { 
       ((LoadingAndErrorViewHolder) holder).setStatus(mFooterStatus); 
       break; 
      } 
      default: { 
       onBindItemViewHolder(holder, position); 
      } 
     } 
    } 

    @Override 
    public void onHeaderLoadingViewHolderClick() { 
     if (mBaseRecyclerAdapterListener != null) { 
      mBaseRecyclerAdapterListener.onErrorHeaderRetryClicked(); 
     } 
    } 

    @Override 
    public void onFooterLoadingViewHolderClick() { 
     if (mBaseRecyclerAdapterListener != null) { 
      mBaseRecyclerAdapterListener.onErrorFooterRetryClicked(); 
     } 
    } 

    public T getItem(int position) { 
     final int headerAdjustment = mHeaderStatus != STATUS_HIDDEN ? 1 : 0; 
     final int adjustedPosition = position - headerAdjustment - mNumOfHeaderItems; 
     if (adjustedPosition < 0 
       || (mFooterStatus != STATUS_HIDDEN && position == getItemCount() - 1)) { 
      return null; 
     } else { 
      return mBackingList.get(adjustedPosition); 
     } 
    } 

    public List<T> getList() { 
     return mBackingList; 
    } 

    public int getListSize() { 
     return mBackingList.size(); 
    } 

    public void setList(List<T> list) { 
     if (list != null) { 
      clear(); 
      add(list); 
     } 
    } 

    public void add(T item) { 
     if (item != null) { 
      mBackingList.add(item); 
      notifyItemInserted(getItemCount() - 1); 
     } 
    } 

    public void add(int index, T item) { 
     if (item != null) { 
      mBackingList.add(index, item); 
      notifyItemInserted(index + getItemOffset()); 
     } 
    } 

    public void add(List<T> list) { 
     if (list != null) { 
      final int currentLastIndex; 
      if (mBackingList.size() > 0) { 
       currentLastIndex = mBackingList.size() - 1; 
      } else { 
       currentLastIndex = 0; 
      } 
      mBackingList.addAll(list); 
      notifyItemRangeInserted(currentLastIndex + getItemOffset(), list.size()); 
     } 
    } 

    public void add(int index, List<T> list) { 
     if (list != null) { 
      mBackingList.addAll(index, list); 
      notifyItemRangeInserted(index + getItemOffset(), list.size()); 
     } 
    } 

    public void update(int position, T item) { 
     mBackingList.set(position, item); 
     notifyItemChanged(position + getItemOffset()); 
    } 

    public void remove(T item) { 
     if (item != null && mBackingList.remove(item)) { 
      notifyDataSetChanged(); 
     } 
    } 

    public void clear() { 
     mBackingList.clear(); 
     notifyDataSetChanged(); 
    } 

    public void setHeaderStatus(int headerStatus) { 
     mHeaderStatus = headerStatus; 
     notifyItemChanged(POSITION_TYPE_HEADER_LOADING); 
    } 

    public void setFooterStatus(int footerStatus) { 
     mFooterStatus = footerStatus; 
     notifyItemChanged(getItemCount() - 1); 
    } 

    public void checkEndOfList(List<T> data) { 
     if (data.isEmpty()) { 
      setFooterStatus(STATUS_HIDDEN); 
     } else { 
      setFooterStatus(STATUS_LOADING); 
     } 
    } 

    protected int getHeaderStatus() { 
     return mHeaderStatus; 
    } 

    protected int getFooterStatus() { 
     return mFooterStatus; 
    } 

    protected abstract RecyclerView.ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType); 

    protected abstract void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position); 

    private int getItemOffset() { 
     final int headerAdjustment = mHeaderStatus != STATUS_HIDDEN ? 1 : 0; 
     return headerAdjustment + mNumOfHeaderItems; 
    } 
} 

堆棧跟蹤

06-01 10:46:36.230 11448-11448/com.fusionprojects.edmodo E/AndroidRuntime: FATAL EXCEPTION: main 
                      Process: com.fusionprojects.edmodo, PID: 11448 
                      java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{dcf5c3a position=23 id=-1, oldPos=23, pLpos:-1 scrap [attachedScrap] tmpDetached no parent} 
                       at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5297) 
                       at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5479) 
                       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440) 
                       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436) 
                       at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224) 
                       at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551) 
                       at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511) 
                       at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595) 
                       at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3534) 
                       at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3310) 
                       at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3844) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:636) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 
                       at android.widget.FrameLayout.onLayout(FrameLayout.java:261) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1795) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741) 
                       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585) 
                       at android.widget.LinearLayout.onLayout(LinearLayout.java:1494) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 
                       at android.widget.FrameLayout.onLayout(FrameLayout.java:261) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 
                       at android.widget.FrameLayout.onLayout(FrameLayout.java:261) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741) 
                       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585) 
                       at android.widget.LinearLayout.onLayout(LinearLayout.java:1494) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 
                       at android.widget.FrameLayout.onLayout(FrameLayout.java:261) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741) 
                       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585) 
                       at android.widget.LinearLayout.onLayout(LinearLayout.java:1494) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 
                       at android.widget.FrameLayout.onLayout(FrameLayout.java:261) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741) 
                       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585) 
06-01 10:46:36.231 11448-11448/com.fusionprojects.edmodo E/AndroidRuntime:  at android.widget.LinearLayout.onLayout(LinearLayout.java:1494) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) 
                       at android.widget.FrameLayout.onLayout(FrameLayout.java:261) 
                       at com.android.internal.policy.DecorView.onLayout(DecorView.java:726) 
                       at android.view.View.layout(View.java:17641) 
                       at android.view.ViewGroup.layout(ViewGroup.java:5575) 
                       at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2346) 
                       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2068) 
                       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254) 
                       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6343) 
                       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874) 
                       at android.view.Choreographer.doCallbacks(Choreographer.java:686) 
                       at android.view.Choreographer.doFrame(Choreographer.java:621) 
                       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860) 
                       at android.os.Handler.handleCallback(Handler.java:751) 
                       at android.os.Handler.dispatchMessage(Handler.java:95) 
                       at android.os.Looper.loop(Looper.java:154) 
                       at android.app.ActivityThread.main(ActivityThread.java:6126) 
                       at java.lang.reflect.Method.invoke(Native Method) 
                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 
+3

可能重複[RecyclerView:檢測到不一致。無效的項目位置](https://stackoverflow.com/questions/30220771/recyclerview-inconsistency-detected-invalid-item-position) –

回答

-1

我在我的setFooterStatus()方法調用notifyDataSetChanged()固定這一點。

相關問題