1. 程式人生 > >RecyclerView報錯:Scrapped or attached views may not be recycled

RecyclerView報錯:Scrapped or attached views may not be recycled

背景

RecyclerView由於需要處理大量資料,它的ViewHolder經常會複用,在效能提高的同時也有可能導致某些View的狀態異常,導致JE問題。

log:

java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true android.support.v7.widget.RecyclerView{3387b42 VFED..... .F...... 0,864-1080,1677 #7f0e0130 app:id/laps_list}, adapter:
[email protected]
, layout:[email protected], context:[email protected]
android.support.v7.widget.RecyclerView$Recycler.recycleViewHolderInternal(RecyclerView.java:5887) android.support.v7.widget.RecyclerView.removeAnimatingView(RecyclerView.java:1350) android.support.v7.widget.RecyclerView
$ItemAnimatorRestoreListener.onAnimationFinished(RecyclerView.java:12015) android.support.v7.widget.RecyclerView$ItemAnimator.dispatchAnimationFinished(RecyclerView.java:12515) android.support.v7.widget.SimpleItemAnimator.dispatchMoveFinished(SimpleItemAnimator.java:293) android.support.v7.widget.DefaultItemAnimator
$6.onAnimationEnd(DefaultItemAnimator.java:311) android.view.ViewPropertyAnimator$AnimatorEventListener.onAnimationEnd(ViewPropertyAnimator.java:1122) android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:552) android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1209) android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1449) android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146) android.animation.AnimationHandler.-wrap2(Unknown Source:0) android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54) android.view.Choreographer$CallbackRecord.run(Choreographer.java:922) android.view.Choreographer.doCallbacks(Choreographer.java:732) android.view.Choreographer.doFrame(Choreographer.java:661) android.view.Choreographer$FrameDisplayEventReceiver.

解法

/frameworks/support/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java

void recycleViewHolderInternal(ViewHolder holder) {
     if (holder.isScrap() || holder.itemView.getParent() != null) {
     //這裡重新判斷一下,如果要複用的ViewHolder還沒有detach,那就從parent裡面移除好了。
        if ((holder.itemView.getParent() != null) 
        && (holder.itemView.getParent() instanceof ViewGroup)) {
            ViewGroup parent = (ViewGroup)(holder.itemView.getParent());
            parent.removeView(holder.itemView);
        } else {
           throw new IllegalArgumentException(
                        "Scrapped or attached views may not be recycled. isScrap:"
                                + holder.isScrap() + " isAttached:"
                                + (holder.itemView.getParent() != null) + exceptionLabel());
                }
            }