RecyclerView的复用缓存机制
前言
在正式分析缓存复用机制时,先去缓存与复用的时机在哪里。在RecyclerView滑动时,item会显示出来。所以首先先想到在onTouchEvent()中ACTION_MOVE事件里做了什么事。
case MotionEvent.ACTION_MOVE:
if (scrollByInternal(
canScrollHorizontally ? dx : 0,
canScrollVertically ? dy : 0,
e)) {
getParent().requestDisallowInterceptTouchEvent(true);
}
接着 又到 scrollStep(x, y, mReusableIntPair) -> mLayout.scrollVerticallyBy(dy, mRecycler, mState)
->scrollBy(dy, recycler, state)[不同的layoutManager有不同的实现,这里以LinearLayoutManager为例]-> fill(recycler, mLayoutState, state)
int fill(RecyclerView.Recycler recycler, LayoutState layoutState,
RecyclerView.State state, boolean stopOnFocusable) {
`````省略
recycleByLayoutState(recycler, layoutState);//回收
layoutChunk(recycler, state, layoutState, layoutChunkResult);//复用
}
复用机制
RecyclerView的缓存分为四级
第一级 mAttachedScrap 和 mChangedScrap:RecyclerView在获取viewHolder时,其中mAttachedScrap 存储的是当前屏幕的和滑出屏幕的ViewHolder,mChangeScrap存储的是数据被更新的ViewHolder。
第二级 mCacheViews :默认的大小为2,通常用来存储预取或者准备回收的ViewHolder。
第三级 ViewCacheExtention:自定义缓存。
第四级 RecyclerViewPool:根据viewType来缓存viewHolder,每个viewType的缓存的viewHolder的个数为5.
接着往源码下找:
layoutState.next(recycler)->getViewForPosition->tryGetViewHolderForPositionByDeadline.到这里就开始RecyclerView的复用流程了。
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
boolean dryRun, long deadlineNs) {
boolean fromScrapOrHiddenOrCache = false;
ViewHolder holder = null;
// 0) If there is a changed scrap, try to find from there
if (mState.isPreLayout()) {
//注释①:第一次查找
holder = getChangedScrapViewForPosition(position);
fromScrapOrHiddenOrCache = holder != null;
}
// 1) Find by position from scrap/hidden list/cache
if (holder == null) {
//注释②:第二次查找
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
if (holder != null) {
if (!validateViewHolderForOffsetPosition(holder)) {
// recycle holder (and unscrap if relevant) since it can't be used
if (!dryRun) {
// we would like to recycle this but need to make sure it is not used by
// animation logic etc.
holder.addFlags(ViewHolder.FLAG_INVALID);
if (holder.isScrap()) {
removeDetachedView(holder.itemView, false);
holder.unScrap();
} else if (holder.wasReturnedFromScrap()) {
holder.clearReturnedFromScrapFlag();
}
recycleViewHolderInternal(holder);
}
holder = null;
} else {
fromScrapOrHiddenOrCache = true;
}
}
}
if (holder == null) {
}
final int type = mAdapter.getItemViewType(offsetPosition);
// 2) Find from scrap/cache via stable ids, if exists
if (mAdapter.hasStableIds()) {
//注释③:第三次查找。
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
type, dryRun);
if (holder != null) {
// update position
holder.mPosition = offsetPosition;
fromScrapOrHiddenOrCache = true;
}
}
if (holder == null && mViewCacheExtension != null) {
t.
//注释④:第四次查找
final View view = mViewCacheExtension
.getViewForPositionAndType(this, position, type);
if (view != null) {
holder = getChildViewHolder(view);
}
}
if (holder == null) { // fallback to pool
//注释⑤:第五次查找
holder = getRecycledViewPool().getRecycledView(type);
if (holder != null) {
holder.resetInternal();
if (FORCE_INVALIDATE_DISPLAY_LIST) {
invalidateDisplayListInt(holder);
}
}
}
if (holder == null) {
long start = getNanoTime();
if (deadlineNs != FOREVER_NS
&& !mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
// abort - we have a deadline we can't meet
return null;
}
//注释⑥:都没找到,去创建
holder = mAdapter.createViewHolder(RecyclerView.this, type);
······
}
注释①:如果有改变的viewHolder,先从mChangedScrap去查找数据被更新的viewHolder,有两种方式,一种是position另一种是id。
注释②:先从mAttachedScrap中查找废弃的ViewHolder,接着再去消失的View中去找有没有可以使用的viewHolder,最后会从mCacheViews(第一级回收缓存) 中去搜索。
注释③:先在mAttachedScrap中查找,再去mCacheViews中去寻找。
注释④:从自定义的缓存策略中去寻找。
注释⑤:从回收池RecyclerViewPool中去找,找到了返回viewHolder并从回收池中移除。
注释⑥:前面都没找到,就调用creatViewHolder去创建viewHolder了。
回收机制
回收主要经历recycleByLayoutState->recycleViewsFromEnd->recycleChildren->removeAndRecycleViewAt-> recycler.recycleView(view)->recycleViewHolderInternal
void recycleViewHolderInternal(ViewHolder holder) {
final boolean transientStatePreventsRecycling = holder
.doesTransientStatePreventRecycling();
@SuppressWarnings("unchecked")
final boolean forceRecycle = mAdapter != null
&& transientStatePreventsRecycling
&& mAdapter.onFailedToRecycleView(holder);
boolean cached = false;
boolean recycled = false;
if (DEBUG && mCachedViews.contains(holder)) {
throw new IllegalArgumentException("cached view received recycle internal? "
+ holder + exceptionLabel());
}
if (forceRecycle || holder.isRecyclable()) {
if (mViewCacheMax > 0
&& !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
| ViewHolder.FLAG_REMOVED
| ViewHolder.FLAG_UPDATE
| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {
// 注释①:第一次回收
int cachedViewSize = mCachedViews.size();
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
recycleCachedViewAt(0);
cachedViewSize--;
}
int targetCacheIndex = cachedViewSize;
if (ALLOW_THREAD_GAP_WORK
&& cachedViewSize > 0
&& !mPrefetchRegistry.lastPrefetchIncludedPosition(holder.mPosition)) {
// when adding the view, skip past most recently prefetched views
int cacheIndex = cachedViewSize - 1;
while (cacheIndex >= 0) {
int cachedPos = mCachedViews.get(cacheIndex).mPosition;
if (!mPrefetchRegistry.lastPrefetchIncludedPosition(cachedPos)) {
break;
}
cacheIndex--;
}
targetCacheIndex = cacheIndex + 1;
}
//注释②:第二次回收
mCachedViews.add(targetCacheIndex, holder);
cached = true;
}
if (!cached) {
addViewHolderToRecycledViewPool(holder, true);
recycled = true;
}
}
mViewInfoStore.removeViewHolder(holder);
if (!cached && !recycled && transientStatePreventsRecycling) {
holder.mOwnerRecyclerView = null;
}
}
注释①:mViewCacheMax 默认为2,如果mCacheViews满了,将它缓存最旧的VH放入回收池,并移除。
注释②:如果没满,就加入到mCacheViews中。