RecyclerView复用回收机制

Recycler组成

RecyclerView的缓存主要委托给了Recycler,先了解下组成

public final class Recycler {
    final ArrayList<RecyclerView.ViewHolder> mAttachedScrap = new ArrayList();
    ArrayList<RecyclerView.ViewHolder> mChangedScrap = null;
    final ArrayList<RecyclerView.ViewHolder> mCachedViews = new ArrayList();
    private final List<RecyclerView.ViewHolder> mUnmodifiableAttachedScrap;
    private int mRequestedCacheMax;
    int mViewCacheMax;
    RecyclerView.RecycledViewPool mRecyclerPool;
    private RecyclerView.ViewCacheExtension mViewCacheExtension;
    static final int DEFAULT_CACHE_SIZE = 2;
    //...
    }
    * 1.一级缓存:mAttachedScrap
    * 2.二级缓存:mCacheViews
    * 3.三级缓存:mViewCacheExtension
    * 4.四级缓存:mRecyclerPool

在RecyclerView的绘制流程中分析过,layoutManager会在layoutChunk方法中对view进行获取添加测量等操作,如下所示

//LinerLayoutManager.java
void layoutChunk(Recycler recycler, State state, LinearLayoutManager.LayoutState layoutState, LinearLayoutManager.LayoutChunkResult result) {
     View view = layoutState.next(recycler);
     // 执行addView
     // 测量view
}
//LinearLayoutManager.LayoutState
View next(Recycler recycler) {
	// mScrapList初始化为空,且仅在layoutForPredictiveAnimations被赋值,执行完后又被设置为null
    if (this.mScrapList != null) {
        return this.nextViewFromScrapList();
    } else {
    	// * 进入该分支
        View view = recycler.getViewForPosition(this.mCurrentPosition);
        this.mCurrentPosition += this.mItemDirection;
        return view;
    }
}
//RecyclerView.Recycler
@NonNull
public View getViewForPosition(int position) {
    return this.getViewForPosition(position, false);
}

View getViewForPosition(int position, boolean dryRun) {
    return this.tryGetViewHolderForPositionByDeadline(position, dryRun, 9223372036854775807L).itemView;
}
tryGetViewHolderForPositionByDeadline

该方法为获取缓存viewHolder核心方法

//RecyclerView.Recycler
@Nullable
RecyclerView.ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {
    if (position >= 0 && position < RecyclerView.this.mState.getItemCount()) {
        boolean fromScrapOrHiddenOrCache = false;
        RecyclerView.ViewHolder holder = null;
        //[0] 从changed Scrap获取holder
        if (RecyclerView.this.mState.isPreLayout()) {
        	//preLayout默认是false,只有有动画的时候才为true?
            holder = this.getChangedScrapViewForPosition(position);
            fromScrapOrHiddenOrCache = holder != null;
        }
		//[1] 从scrap中获取holder
        if (holder == null) {
            holder = this.getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
            if (holder != null) {
            	// 检查该holder是否与holder对应postion
                if (!this.validateViewHolderForOffsetPosition(holder)) {
                	// 如果信息不符
                    if (!dryRun) {
                        holder.addFlags(4);
                       	// 从scrap移除
                        if (holder.isScrap()) {
                            RecyclerView.this.removeDetachedView(holder.itemView, false);
                            holder.unScrap();
                        } else if (holder.wasReturnedFromScrap()) {
                            holder.clearReturnedFromScrapFlag();
                        }
						// 将该holder放入mCachedViews或者mRecyclerPool中
                        this.recycleViewHolderInternal(holder);
                    }
					//设置为空
                    holder = null;
                } else {
                    fromScrapOrHiddenOrCache = true;
                }
            }
        }

        int offsetPosition;
        int type;
        if (holder == null) {
            offsetPosition = RecyclerView.this.mAdapterHelper.findPositionOffset(position);
            if (offsetPosition < 0 || offsetPosition >= RecyclerView.this.mAdapter.getItemCount()) {
                throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item position " + position + "(offset:" + offsetPosition + ")." + "state:" + RecyclerView.this.mState.getItemCount() + RecyclerView.this.exceptionLabel());
            }

            type = RecyclerView.this.mAdapter.getItemViewType(offsetPosition);
            if (RecyclerView.this.mAdapter.hasStableIds()) {
                holder = this.getScrapOrCachedViewForId(RecyclerView.this.mAdapter.getItemId(offsetPosition), type, dryRun);
                if (holder != null) {
                    holder.mPosition = offsetPosition;
                    fromScrapOrHiddenOrCache = true;
                }
            }
			// 自定义缓存
            if (holder == null && this.mViewCacheExtension != null) {
                View view = this.mViewCacheExtension.getViewForPositionAndType(this, position, type);
                if (view != null) {
                    holder = RecyclerView.this.getChildViewHolder(view);
                    if (holder == null) {
                        throw new IllegalArgumentException("getViewForPositionAndType returned a view which does not have a ViewHolder" + RecyclerView.this.exceptionLabel());
                    }

                    if (holder.shouldIgnore()) {
                        throw new IllegalArgumentException("getViewForPositionAndType returned a view that is ignored. You must call stopIgnoring before returning this view." + RecyclerView.this.exceptionLabel());
                    }
                }
            }
			// 从缓存池中获取
            if (holder == null) {
                holder = this.getRecycledViewPool().getRecycledView(type);
                if (holder != null) {
                    holder.resetInternal();
                    if (RecyclerView.FORCE_INVALIDATE_DISPLAY_LIST) {
                        this.invalidateDisplayListInt(holder);
                    }
                }
            }
			// 创建
            if (holder == null) {
                long start = RecyclerView.this.getNanoTime();
                if (deadlineNs != 9223372036854775807L && !this.mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
                    return null;
                }

                holder = RecyclerView.this.mAdapter.createViewHolder(RecyclerView.this, type);
                if (RecyclerView.ALLOW_THREAD_GAP_WORK) {
                    RecyclerView innerView = RecyclerView.findNestedRecyclerView(holder.itemView);
                    if (innerView != null) {
                        holder.mNestedRecyclerView = new WeakReference(innerView);
                    }
                }

                long end = RecyclerView.this.getNanoTime();
                this.mRecyclerPool.factorInCreateTime(type, end - start);
            }
        }
        
        if (RecyclerView.this.mState.isPreLayout() && holder.isBound()) {
            holder.mPreLayoutPosition = position;
        } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
        	// 如果ViewHolder是从recyclerPool中拿到的,由于其ViewHolder信息初始化则需要进行bindViewHolder
            type = RecyclerView.this.mAdapterHelper.findPositionOffset(position);
            bound = this.tryBindViewHolderByDeadline(holder, type, position, deadlineNs);
        }
      // .......  
       return holder;
    } else {
        throw new IndexOutOfBoundsException("Invalid item position " + position + "(" + position + "). Item count:" + RecyclerView.this.mState.getItemCount() + RecyclerView.this.exceptionLabel());
    }
}
if (RecyclerView.this.mState.isPreLayout()) {
	//preLayout默认是false,只有有动画的时候才为true?
    holder = this.getChangedScrapViewForPosition(position);
    fromScrapOrHiddenOrCache = holder != null;
}
//RecyclerView.State
 public boolean isPreLayout() {
     return this.mInPreLayout;
 }
=> this.mState.mInPreLayout = this.mState.mRunPredictiveAnimations;
=> this.mState.mRunPredictiveAnimations = this.mState.mRunSimpleAnimations && animationTypeSupported && !this.mDataSetHasChangedAfterLayout && this.predictiveItemAnimationsEnabled();
// 唉,索引到这里我已经晕了,有的博主说当动画执行的时候为true
1、依据position从mAttachedScrap/HiddenViews/mCachedViews中获取holder
if (holder == null) {
    holder = this.getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
    if (holder != null) {
    	// 检验从scrap货cache获取的holder是否与position对应
        if (!this.validateViewHolderForOffsetPosition(holder)) {
            if (!dryRun) {
                holder.addFlags(4);
                // 如果信息不符合 scrap中移除该scrap
                if (holder.isScrap()) {
                    RecyclerView.this.removeDetachedView(holder.itemView, false);
                    holder.unScrap();
                } else if (holder.wasReturnedFromScrap()) {
                    holder.clearReturnedFromScrapFlag();
                }
                // 将该holder放入mCachedViews或mRecyclerPool
                this.recycleViewHolderInternal(holder);
            }
            holder = null;
        } else {
            fromScrapOrHiddenOrCache = true;
        }
    }
}
RecyclerView.ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) {
    int scrapCount = this.mAttachedScrap.size();

    int cacheSize;
    RecyclerView.ViewHolder vh;
    // **[1] for循环遍历mAttachedScrap获取postion相等的viewHolder
    for(cacheSize = 0; cacheSize < scrapCount; ++cacheSize) {
        vh = (RecyclerView.ViewHolder)this.mAttachedScrap.get(cacheSize);
        if (!vh.wasReturnedFromScrap() && vh.getLayoutPosition() == position && !vh.isInvalid() && (RecyclerView.this.mState.mInPreLayout || !vh.isRemoved())) {
            vh.addFlags(32);
            return vh;
        }
    }
	// dryRun为false
    if (!dryRun) {
    	// **[2]从隐藏但没有移除的view中寻找
    	// todo 在哪里进行添加的?
        View view = RecyclerView.this.mChildHelper.findHiddenNonRemovedView(position);
        if (view != null) {
            vh = RecyclerView.getChildViewHolderInt(view);
            RecyclerView.this.mChildHelper.unhide(view);
            int layoutIndex = RecyclerView.this.mChildHelper.indexOfChild(view);
            if (layoutIndex == -1) {
                throw new IllegalStateException("layout index should not be -1 after unhiding a view:" + vh + RecyclerView.this.exceptionLabel());
            }
RecyclerView.this.mChildHelper.detachViewFromParent(layoutIndex);
			// scrap缓存holder
            this.scrapView(view);
            vh.addFlags(8224);
            return vh;
        }
    }

    cacheSize = this.mCachedViews.size();
	// ** [3] 从CacheViews中去获取
    for(int i = 0; i < cacheSize; ++i) {
        RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)this.mCachedViews.get(i);
        if (!holder.isInvalid() && holder.getLayoutPosition() == position) {
            if (!dryRun) {
                this.mCachedViews.remove(i);
            }

            return holder;
        }
    }
    return null;
}
type = RecyclerView.this.mAdapter.getItemViewType(offsetPosition);
 if (RecyclerView.this.mAdapter.hasStableIds()) {
     holder = this.getScrapOrCachedViewForId(RecyclerView.this.mAdapter.getItemId(offsetPosition), type, dryRun);
     if (holder != null) {
         holder.mPosition = offsetPosition;
         fromScrapOrHiddenOrCache = true;
     }
 }

mHasStableIds在Adapter中默认是false,而修改其值的api如下所示,
当我们在对Adapter设置setHasStableIds(true)时,注意得重写getItemId

public void setHasStableIds(boolean hasStableIds) {
    if (this.hasObservers()) {
        throw new IllegalStateException("Cannot change whether this adapter has stable IDs while the adapter has registered observers.");
    } else {
        this.mHasStableIds = hasStableIds;
    }
}
2、依据ID type从mAttachedScrap和CacheView中获取holder
RecyclerView.ViewHolder getScrapOrCachedViewForId(long id, int type, boolean dryRun) {
    int count = this.mAttachedScrap.size();
    int i;
    // for循环遍历mAttachedScrap,找出id相等的holder
    for(i = count - 1; i >= 0; --i) {
        RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)this.mAttachedScrap.get(i);
        if (holder.getItemId() == id && !holder.wasReturnedFromScrap()) {
            if (type == holder.getItemViewType()) {
                holder.addFlags(32);
                if (holder.isRemoved() && !RecyclerView.this.mState.isPreLayout()) {
                    holder.setFlags(2, 14);
                }

                return holder;
            }
            if (!dryRun) {
                this.mAttachedScrap.remove(i);
                RecyclerView.this.removeDetachedView(holder.itemView, false);
                this.quickRecycleScrapView(holder.itemView);
            }
        }
    }
    // 以ID为判断标准从CachedView中寻找holder
    i = this.mCachedViews.size();
    for(int ix = i - 1; ix >= 0; --ix) {
        RecyclerView.ViewHolder holderx = (RecyclerView.ViewHolder)this.mCachedViews.get(ix);
        if (holderx.getItemId() == id) {
            if (type == holderx.getItemViewType()) {
                if (!dryRun) {
                    this.mCachedViews.remove(ix);
                }

                return holderx;
            }
            if (!dryRun) {
                this.recycleCachedViewAt(ix);
                return null;
            }
        }
    }
    return null;
}
3、自定义缓存获取holder
4、依据type从mRecyclerPool获取holder
if (holder == null) {
    holder = this.getRecycledViewPool().getRecycledView(type);
    if (holder != null) {
        holder.resetInternal();
        if (RecyclerView.FORCE_INVALIDATE_DISPLAY_LIST) {
            this.invalidateDisplayListInt(holder);
        }
    }
}
5、缓存都没有重新创建
if (holder == null) {
    long start = RecyclerView.this.getNanoTime();
    if (deadlineNs != 9223372036854775807L && !this.mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
        return null;
    }
    holder = RecyclerView.this.mAdapter.createViewHolder(RecyclerView.this, type);
    if (RecyclerView.ALLOW_THREAD_GAP_WORK) {
        RecyclerView innerView = RecyclerView.findNestedRecyclerView(holder.itemView);
        if (innerView != null) {
            holder.mNestedRecyclerView = new WeakReference(innerView);
        }
    }

    long end = RecyclerView.this.getNanoTime();
    this.mRecyclerPool.factorInCreateTime(type, end - start);
}

问题探究

Q1: mAttachedScrap何时缓存列表数据?何时销毁缓存?

首先探索何时赋值,我们逆着推Recycler中mAttachedScrap何时调用的
mAttachedScrap 缓存holder

// RecyclerView.java
public final class Recycler {
	void scrapView(View view) {
	   ....
	   this.mAttachedScrap.add(holder);
	}
}
// RecyclerView.java
public abstract static class LayoutManager {
	// .....
	private void scrapOrRecycleView(RecyclerView.Recycler recycler, int index, View view) {
	    RecyclerView.ViewHolder viewHolder = RecyclerView.getChildViewHolderInt(view);
	    if (!viewHolder.shouldIgnore()) {
	        if (viewHolder.isInvalid() && !viewHolder.isRemoved() && !this.mRecyclerView.mAdapter.hasStableIds()) {
	        	// layoutManager删除该项
	            this.removeViewAt(index);
	            // 将holder放入cacheView或recyclerViewPool中
	            recycler.recycleViewHolderInternal(viewHolder);
	        } else {
	            this.detachViewAt(index);
	            // 将view加入mAttchScraps中
	            recycler.scrapView(view);
	            this.mRecyclerView.mViewInfoStore.onViewDetached(viewHolder);
	        }
	    }
	}
	
	=>  // scrapOrRecycleView 在该方法中调用
   public void detachAndScrapAttachedViews(@NonNull RecyclerView.Recycler recycler) {
   	   // 获取layout可见的布局  	
       int childCount = this.getChildCount();
       for(int i = childCount - 1; i >= 0; --i) {
           View v = this.getChildAt(i);
           // 调用
           this.scrapOrRecycleView(recycler, i, v);
       }

   }
}
//LinearlayoutManager.java
public class LinearLayoutManager extends LayoutManager{
	public void onLayoutChildren(Recycler recycler, State state) {
		  // 在fill之前
		  // 在填充表项之前回收所有表项
		  this.detachAndScrapAttachedViews(recycler);
		  //...
		  this.fill(recycler, this.mLayoutState, state, false);
	}
	// onLayoutChildren 就是在 dispatchLayoutStep2()进行的调用
}

在将表项一个个填充到列表之前会先将其先回收到mAttachedScrap中,回收数据的来源是LayoutManager的孩子,而LayoutManager的孩子都是屏幕上可见的数据项。
mAttachedScrap用于屏幕中可见数据项的回收和复用

mAttachedScrap 清除缓存

//RecyclerView.java
public final class Recycler{
	 void clearScrap() {
	     this.mAttachedScrap.clear();
	     if (this.mChangedScrap != null) {
	         this.mChangedScrap.clear();
	     }
	 }
}
// RecyclerView.java
public abstract static class LayoutManager {
        /**
         * Recycles the scrapped views.
         * 回收所有scrapped view
         */
        void removeAndRecycleScrapInt(Recycler recycler) {
            final int scrapCount = recycler.getScrapCount();
            // Loop backward, recycler might be changed by removeDetachedView()
            //遍历搜有scrap view并重置ViewHolder状态
            for (int i = scrapCount - 1; i >= 0; i--) {
                final View scrap = recycler.getScrapViewAt(i);
                final ViewHolder vh = getChildViewHolderInt(scrap);
                if (vh.shouldIgnore()) {
                    continue;
                }
                vh.setIsRecyclable(false);
                if (vh.isTmpDetached()) {
                    mRecyclerView.removeDetachedView(scrap, false);
                }
                if (mRecyclerView.mItemAnimator != null) {
                    mRecyclerView.mItemAnimator.endAnimation(vh);
                }
                vh.setIsRecyclable(true);
                recycler.quickRecycleScrapView(scrap);
            }
            //清空scrap view集合
            recycler.clearScrap();
            if (scrapCount > 0) {
                mRecyclerView.invalidate();
            }
        }
}
private void dispatchLayoutStep3() {
	//....
	this.mLayout.removeAndRecycleScrapInt(this.mRecycler);
	//....
}

mAttachedScrap 就是在开始布局前设置缓存,在布局结束后清除缓存。
主要用于屏幕间可见数据的回收和复用。

Recycler回收机制

RecyclerView滑动时,当有可用空间时,首先会从缓存或重新创建view,然后进行添加,然后会依据顶部或底部的view是否会滑出屏幕,如果是的话,会进行回收,添加入CacheViews中。
从缓存中获取view时,如果CachedViews中存在,则会将holder从list中删除并返回;
如果cacheViews中找不到,则会从RecyclerPool中依据type进行寻找,找到之后还需执行bindViewHolder刷新数据。

   // RecyclerView.java	
   void scrollStep(int dx, int dy, @Nullable int[] consumed) {
   		//....
        if (dy != 0) {
            consumedY = this.mLayout.scrollVerticallyBy(dy, this.mRecycler, this.mState);
        }
}
 //LinearLayoutManager
 public int scrollVerticallyBy(int dy, Recycler recycler, State state) {
     return this.mOrientation == 0 ? 0 : this.scrollBy(dy, recycler, state);
 }

int scrollBy(int dy, Recycler recycler, State state) {
    int consumed = this.mLayoutState.mScrollingOffset + this.fill(recycler, this.mLayoutState, state, false);
    //...
}
	//LinearLayoutManager
int fill(Recycler recycler, LinearLayoutManager.LayoutState layoutState, State state, boolean stopOnFocusable) {
    while((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
        layoutChunkResult.resetInternal();
        this.layoutChunk(recycler, state, layoutState, layoutChunkResult);
        // ....
        if (layoutState.mScrollingOffset != -2147483648) {
            this.recycleByLayoutState(recycler, layoutState);
        }
    }
    return start - layoutState.mAvailable;
}
//RecyclerView.java
private void recycleByLayoutState(Recycler recycler, LinearLayoutManager.LayoutState layoutState) {
    if (layoutState.mRecycle && !layoutState.mInfinite) {
        if (layoutState.mLayoutDirection == -1) {
            this.recycleViewsFromEnd(recycler, layoutState.mScrollingOffset);
        } else {
            this.recycleViewsFromStart(recycler, layoutState.mScrollingOffset);
        }

    }
}

private void recycleViewsFromStart(Recycler recycler, int dt) {
    if (dt >= 0) {
        int limit = dt;
        int childCount = this.getChildCount();
        int i;
        View child;
        if (this.mShouldReverseLayout) {
            for(i = childCount - 1; i >= 0; --i) {
                child = this.getChildAt(i);
                if (this.mOrientationHelper.getDecoratedEnd(child) > limit || this.mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
                    this.recycleChildren(recycler, childCount - 1, i);
                    return;
                }
            }
        } else {
            for(i = 0; i < childCount; ++i) {
                child = this.getChildAt(i);
                if (this.mOrientationHelper.getDecoratedEnd(child) > limit || this.mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
                    this.recycleChildren(recycler, 0, i);
                    return;
                }
            }
        }

    }
}

private void recycleChildren(Recycler recycler, int startIndex, int endIndex) {
    if (startIndex != endIndex) {
        int i;
        if (endIndex > startIndex) {
            for(i = endIndex - 1; i >= startIndex; --i) {
                this.removeAndRecycleViewAt(i, recycler);
            }
        } else {
            for(i = startIndex; i > endIndex; --i) {
                this.removeAndRecycleViewAt(i, recycler);
            }
        }

    }
}

public void removeAndRecycleViewAt(int index, @NonNull RecyclerView.Recycler recycler) {
    View view = this.getChildAt(index);
    this.removeViewAt(index);
    recycler.recycleView(view);
}

回收滑出屏幕对应的ViewHolder

# RecyclerView.Recycler
public void recycleView(@NonNull View view) {
    RecyclerView.ViewHolder holder = RecyclerView.getChildViewHolderInt(view);
    if (holder.isTmpDetached()) {
        RecyclerView.this.removeDetachedView(view, false);
    }

    if (holder.isScrap()) {
        holder.unScrap();
    } else if (holder.wasReturnedFromScrap()) {
        holder.clearReturnedFromScrapFlag();
    }

    this.recycleViewHolderInternal(holder);
}

void recycleViewHolderInternal(RecyclerView.ViewHolder holder) {
	// ....
  if (forceRecycle || holder.isRecyclable()) {
     if (this.mViewCacheMax > 0 && !holder.hasAnyOfTheFlags(526)) {
         int cachedViewSize = this.mCachedViews.size();
         // 当缓存的数量大于最大缓存数量时,mCachedViews会移除最老的一个view
         if (cachedViewSize >= this.mViewCacheMax && cachedViewSize > 0) {
         	// 移除cacheView中数据
             this.recycleCachedViewAt(0);
             --cachedViewSize;
         }
         int targetCacheIndex = cachedViewSize;
         if (RecyclerView.ALLOW_THREAD_GAP_WORK && cachedViewSize > 0 && !RecyclerView.this.mPrefetchRegistry.lastPrefetchIncludedPosition(holder.mPosition)) {
             int cacheIndex;
             for(cacheIndex = cachedViewSize - 1; cacheIndex >= 0; --cacheIndex) {
                 int cachedPos = ((RecyclerView.ViewHolder)this.mCachedViews.get(cacheIndex)).mPosition;
                 if (!RecyclerView.this.mPrefetchRegistry.lastPrefetchIncludedPosition(cachedPos)) {
                     break;
                 }
             }
             targetCacheIndex = cacheIndex + 1;
         }
		 // ** 将holder加入mCacheViews中	
         this.mCachedViews.add(targetCacheIndex, holder);
         cached = true;
     }

     if (!cached) {
     	 // 如果没有加入mCacheViews则将holder加入RecyclerPool中
         this.addViewHolderToRecycledViewPool(holder, true);
         recycled = true;
     }
 }
}
//RecyclerView.java
// 将mCacheViews中ViewHolder放入recyclerPool中
public final class Recycler{
	void recycleCachedViewAt(int cachedViewIndex) {
	    RecyclerView.ViewHolder viewHolder = (RecyclerView.ViewHolder)this.mCachedViews.get(cachedViewIndex);
	    this.addViewHolderToRecycledViewPool(viewHolder, true);
	    this.mCachedViews.remove(cachedViewIndex);
	}
}

从mCachedViews移除掉的ViewHolder会加入到回收池中。 mCachedViews有点像“回收池预备队列”,即总是先回收到mCachedViews,当它放不下的时候,按照先进先出原则将最先进入的ViewHolder存入回收池

// RecyclerView.java
public staitic final Recycler{
  void addViewHolderToRecycledViewPool(@NonNull RecyclerView.ViewHolder holder, boolean dispatchRecycled) {
      if (dispatchRecycled) {
          this.dispatchViewRecycled(holder);
      }
      holder.mOwnerRecyclerView = null;
      this.getRecycledViewPool().putRecycledView(holder);
  }
  
 // 进行一些回调 
 void dispatchViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
     if (RecyclerView.this.mRecyclerListener != null) {
         RecyclerView.this.mRecyclerListener.onViewRecycled(holder);
     }
     if (RecyclerView.this.mAdapter != null) {
         RecyclerView.this.mAdapter.onViewRecycled(holder);
     }
     if (RecyclerView.this.mState != null) {
         RecyclerView.this.mViewInfoStore.removeViewHolder(holder);
     }
 }
}
// RecyclerView.java
public static class RecycledViewPool {
  public void putRecycledView(RecyclerView.ViewHolder scrap) {
      int viewType = scrap.getItemViewType();
      ArrayList<RecyclerView.ViewHolder> scrapHeap = this.getScrapDataForType(viewType).mScrapHeap;
      if (((RecyclerView.RecycledViewPool.ScrapData)this.mScrap.get(viewType)).mMaxScrap > scrapHeap.size()) {
      	  // 在缓存前重置ViewHolder内部信息,包括position,itemID之类
      	  // 这样下次从recyclerPool中拿出来复用时就可以当一个新的ViewHolder使用
          scrap.resetInternal();
          scrapHeap.add(scrap);
      }
  }
  
void resetInternal() {
     this.mFlags = 0;
     this.mPosition = -1;
     this.mOldPosition = -1;
     this.mItemId = -1L;
     this.mPreLayoutPosition = -1;
     this.mIsRecyclableCount = 0;
     this.mShadowedHolder = null;
     this.mShadowingHolder = null;
     this.clearPayload();
     this.mWasImportantForAccessibilityBeforeHidden = 0;
     this.mPendingAccessibilityState = -1;
     RecyclerView.clearNestedRecyclerViewIfNotNested(this);
 }
}
Q: mCachedViews中 mViewCacheMax默认值时是多少?可以修改?如何修改呢?
// RecyclerView.java
public final class Recycler {
  public Recycler() {
     this.mUnmodifiableAttachedScrap = Collections.unmodifiableList(this.mAttachedScrap);
     this.mRequestedCacheMax = 2;
     
     this.mViewCacheMax = 2;
  }
  
	public void setViewCacheSize(int viewCount) {
	    this.mRequestedCacheMax = viewCount;
	    this.updateViewCacheSize();
	}
	// 更新缓存的最大数量
	void updateViewCacheSize() {
	    int extraCache = RecyclerView.this.mLayout != null ? RecyclerView.this.mLayout.mPrefetchMaxCountObserved : 0// 设置最大缓存数量
	    this.mViewCacheMax = this.mRequestedCacheMax + extraCache;
	    for(int i = this.mCachedViews.size() - 1; i >= 0 && this.mCachedViews.size() > this.mViewCacheMax; --i) {
	        this.recycleCachedViewAt(i);
	    }
	
	}
}
 // RecyclerView.java
 public void setItemViewCacheSize(int size) {
     this.mRecycler.setViewCacheSize(size);
 }

mCacheViews默认缓存的数量是2,我们可通过调用RecyclerView的setItemViewCacheSize来设置Recycler中mCacheViews的最大数量

计算平移的距离,遍历子view进行平移滑动平移

public void offsetChildrenVertical(@Px int dy) {
    int childCount = this.mChildHelper.getChildCount();

    for(int i = 0; i < childCount; ++i) {
        this.mChildHelper.getChildAt(i).offsetTopAndBottom(dy);
    }

}

你可能感兴趣的:(经典源码)