RecyclerView缓存(2111)复用(1211)机制源码详解

160 阅读3分钟

缓存scrapOrRecycleView()

根据条件判断 -> 一级缓存 / 二、四级缓存

private void scrapOrRecycleView(Recycler recycler, int index, View view) {
    final ViewHolder viewHolder = getChildViewHolderInt(view);
    if (viewHolder.shouldIgnore()) {
        if (DEBUG) {
            Log.d(TAG, "ignoring view " + viewHolder);
        }
        return;
    }
    if (viewHolder.isInvalid() && !viewHolder.isRemoved()
            && !mRecyclerView.mAdapter.hasStableIds()) {
        removeViewAt(index); // 移除视图
        recycler.recycleViewHolderInternal(viewHolder); // 二、四级缓存
    } else {
        detachViewAt(index); // 暂时从视图层级结构中分离视图
        recycler.scrapView(view); // 一级缓存
        mRecyclerView.mViewInfoStore.onViewDetached(viewHolder);
    }
}

scrapView(View view)

public final class Recycler {
    // ArrayList -> 存储屏幕中的ViewHolder
    final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
    ArrayList<ViewHolder> mChangedScrap = null;
    //……
    void scrapView(View view) {
        final ViewHolder holder = getChildViewHolderInt(view);

mAttachedScrap

        if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
                || !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {
            //……
            holder.setScrapContainer(this, false);
            mAttachedScrap.add(holder); // 缓存屏幕中未改变的ViewHolder
        } else {

mChangedScrap

            if (mChangedScrap == null) {
                mChangedScrap = new ArrayList<ViewHolder>();
            }
            holder.setScrapContainer(this, true);
            mChangedScrap.add(holder); // 缓存屏幕中如`notifyItemChanged`改变的ViewHolder
        }
    }

recycleViewHolderInternal(viewHolder)

void recycleViewHolderInternal(ViewHolder holder) {
    // ……省略这部分异常处理及条件参数的设置
    if (forceRecycle || holder.isRecyclable()) {
        if (mViewCacheMax > 0 // mViewCacheMax = DEFAULT_CACHE_SIZE = 2 默认2个
                && !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
                | ViewHolder.FLAG_REMOVED
                | ViewHolder.FLAG_UPDATE
                | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {

mCachedView

            // Retire oldest cached view 
            int cachedViewSize = mCachedViews.size();
            if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
                // 二级缓存已满且新ViewHolder进入 -> 最早添加的ViewHolder -> RecycledViewPool
                recycleCachedViewAt(0); 
                cachedViewSize--;
            }
            
            // 计算targetCacheIndex,避免向缓存中添加新的视图时,覆盖最近预取的视图
            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;
        }
  • 缓存池RecycledViewPool
        // -> 缓存池RecycledViewPool
        if (!cached) {
            addViewHolderToRecycledViewPool(holder, true);
            recycled = true;
        }
    } else { // ……动画过程中回收 -> 异常信息 }
    // even if the holder is not removed, we still call this method so that it is removed
    // from view holder lists.
    mViewInfoStore.removeViewHolder(holder);
    if (!cached && !recycled && transientStatePreventsRecycling) {
        holder.mOwnerRecyclerView = null;
    }
}

自定义缓存ViewCacheExtension

void setViewCacheExtension(ViewCacheExtension extension) {
    mViewCacheExtension = extension;
}

addViewHolderToRecycledViewPool(holder, true)

void addViewHolderToRecycledViewPool(@NonNull ViewHolder holder, boolean dispatchRecycled) {
    clearNestedRecyclerViewIfNotNested(holder); // 清除ViewHolder绑定的数据
    View itemView = holder.itemView;
    // ……
    if (dispatchRecycled) {
        dispatchViewRecycled(holder);
    }
    holder.mOwnerRecyclerView = null;
    // 添加到缓存池`RecycledViewPool`中
    getRecycledViewPool().putRecycledView(holder); // DEFAULT_MAX_SCRAP = 5
}

putRecycledView(ViewHolder scrap)

public void putRecycledView(ViewHolder scrap) {
    final int viewType = scrap.getItemViewType();
    final ArrayList<ViewHolder> scrapHeap = getScrapDataForType(viewType).mScrapHeap;
    
    // 每种类型viewType的ViewHolder -> 默认mMaxScrap = DEFAULT_MAX_SCRAP = 5
    if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) { // SparseArray<ScrapData> mScrap = new SparseArray<>();
        return;
    }
    if (DEBUG && scrapHeap.contains(scrap)) {
        throw new IllegalArgumentException("this scrap item already exists");
    }
    scrap.resetInternal();
    scrapHeap.add(scrap);
}

image.png

image.png

复用tryGetViewHolderForPositionByDeadline()

getViewForPosition(int position) -> getViewForPosition(position, false) -> tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView

ViewHolder tryGetViewHolderForPositionByDeadline(int position,
        boolean dryRun, long deadlineNs) {
    //……

mChangedScrap

    // 0) If there is a changed scrap, try to find from there 
    if (mState.isPreLayout()) {
        holder = getChangedScrapViewForPosition(position); // position/id -> mChangedScrap
        fromScrapOrHiddenOrCache = holder != null;
    }

position -> mAttachedScrap/mCachedView

    // 1) Find by position from scrap/hidden list/cache
    if (holder == null) {
        // position -> mAttachedScrap/(mCachedView源码注释:Search in our first-level recycled view cache.)
        holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun); 
        if (holder != null) {
            if (!validateViewHolderForOffsetPosition(holder)) { // 如果找到的ViewHolder不可用 -> 回收 -> RecycledViewPool
                // recycle holder (and unscrap if relevant) since it can't be used
                if (!dryRun) {
                    // ……省略回收前的一些处理
                    recycleViewHolderInternal(holder);
                }
                holder = null;
            } else {
                fromScrapOrHiddenOrCache = true;
            }
        }
    }
    if (holder == null) {
        final int offsetPosition = mAdapterHelper.findPositionOffset(position);
        // ……
        final int type = mAdapter.getItemViewType(offsetPosition);

id -> mAttachedScrap/mCachedView

        // 2) Find from scrap/cache via stable ids, if exists
        if (mAdapter.hasStableIds()) {
            // id -> mAttachedScrap/mCachedView
            holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
                    type, dryRun);
            if (holder != null) {
                // update position
                holder.mPosition = offsetPosition;
                fromScrapOrHiddenOrCache = true;
            }
        }

自定义缓存ViewCacheExtension

        // 自定义缓存 `mViewCacheExtension != null`
        if (holder == null && mViewCacheExtension != null) {
            // We are NOT sending the offsetPosition because LayoutManager does not
            // know it.
            final View view = mViewCacheExtension
                    .getViewForPositionAndType(this, position, type);
            if (view != null) {
                holder = getChildViewHolder(view);
                //……省略部分`holder == null`的异常处理
            }
        }

RecycledViewPool

  • 注:默认每种类型ViewType -> 缓存5个ViewHolder
        // 从`RecycledViewPool`中找到对应类型的ViewHolder
        if (holder == null) { // fallback to pool
            //……省略调试代码块
            holder = getRecycledViewPool().getRecycledView(type);
            if (holder != null) {
                holder.resetInternal();
                if (FORCE_INVALIDATE_DISPLAY_LIST) {
                    invalidateDisplayListInt(holder);
                }
            }
        }

onCreateViewHolder()

        // 最终策略:onCreateViewHolder()
        if (holder == null) {
            //……
            holder = mAdapter.createViewHolder(RecyclerView.this, type);
            //……
        }

项目onCreateonBind方法调用次数统计

最后,是统计onCreateViewHolderonBindViewHolder方法调用次数,LogCat中打印的项目

userbiliy/RecyclerView: onCreateViewHolder和onBindViewHolder方法调用次数测试日志 (github.com)

  • 注意:图片里的编号仅是个编号,与次序无关,具体次序看上下滑动顺序

image.png