LayoutManager gets views through Recycler, so its caching mechanism must be Recycler

RecyclerView layout process design

The entry to the View is in the getViewForPosition method:

# Recycler public View getViewForPosition(int position) { return getViewForPosition(position, false); } View getViewForPosition(int position, boolean dryRun) { // ViewHolder.itemView return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView; } ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) { // 0.from changed scrap if (mState.isPreLayout()) { holder = getChangedScrapViewForPosition(position); fromScrapOrHiddenOrCache = holder ! = null; } // 1.from scrap/hidden list/cache holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun); // 2.from scrap/cache via stable ids, if exists if (mAdapter.hasStableIds()) { holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun); } // 3.recyclerview pool holder = getRecycledViewPool().getRecycledView(type); // 4.create new viewholder holder = mAdapter.createViewHolder(RecyclerView.this, type); }Copy the code

Steps 0-3 retrieve the ViewHolder from the cache

0.getChangedScrapViewForPosition -> mChangedScrap

MChangedScrap: ViewHolder to store data changes

ArrayList<ViewHolder> mChangedScrap = null; ViewHolder getChangedScrapViewForPosition(int position) { // mChangedScrap for (int i = 0; i < changedScrapSize; i++) { final ViewHolder holder = mChangedScrap.get(i); if (! holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position) { holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP); return holder; } } return null; }Copy the code

1. GetScrapOrHiddenOrCachedHolderForPosition – > mAttachedScrap, ChildHelper. MHiddenViews, mCachedViews

  • MAttachedScrap: All are temporarily cached during a relayoutViewHolder
  • MHiddenViews: Temporary save hiddenItemView, for example, do before and then do the departure animationItemViewAnd for some reason needs to be used when they come in.
  • MCachedViews: level 1 cache in the real sense, the previous is only temporary storage, called staging area is more reasonable
ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>(); final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>(); ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) { // 1.attachedScrap for (int i = 0; i < scrapCount; i++) { final ViewHolder holder = mAttachedScrap.get(i); return holder; } // 2.ChildHelper.mHiddenViews View view = mChildHelper.findHiddenNonRemovedView(position); if (view ! = null) { ViewHolder vh = getChildViewHolderInt(view); return vh; } // 3.mCachedViews: first-level recycled view cache int cacheSize = mCachedViews.size(); for (int i = 0; i < cacheSize; i++) { final ViewHolder holder = mCachedViews.get(i); return holder; } return null; }Copy the code

2. GetScrapOrCachedViewForId – > mAttachedScrap, mCachedViews

This logic is invoked only if mHasStableIds are set.

Find ViewHolder from mAttachedScrap and mCachedViews based on itemId instead of position.

// mAttachedScrap ViewHolder getScrapOrCachedViewForId(long id, int type, boolean dryRun) { final int count = mAttachedScrap.size(); for (int i = count - 1; i >= 0; i--) { final ViewHolder holder = mAttachedScrap.get(i); if (holder.getItemId() == id && ! holder.wasReturnedFromScrap()) { return holder; } final int cacheSize = mCachedViews.size(); for (int i = cacheSize - 1; i >= 0; i--) { final ViewHolder holder = mCachedViews.get(i); if (holder.getItemId() == id && ! holder.isAttachedToTransitionOverlay()) { return holder; } return null; }Copy the code

Consider: What does hasStableId do?

3.RecycledViewPool -> mScrap

RecycledViewPool getRecycledView(type); RecycledViewPool getRecycledView(type);

# Recycler holder = getRecycledViewPool().getRecycledView(type); # RecycledViewPool final int type = mAdapter.getItemViewType(offsetPosition); SparseArray<ScrapData> mScrap = new SparseArray<>(); public ViewHolder getRecycledView(int viewType) { final ScrapData scrapData = mScrap.get(viewType); if (scrapData ! = null && ! scrapData.mScrapHeap.isEmpty()) { final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap; for (int i = scrapHeap.size() - 1; i >= 0; i--) { if (! scrapHeap.get(i).isAttachedToTransitionOverlay()) { return scrapHeap.remove(i); } } } return null; } static class ScrapData { final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>(); int mMaxScrap = DEFAULT_MAX_SCRAP; long mCreateRunningAverageNs = 0; long mBindRunningAverageNs = 0; }Copy the code

4.mAdapter.createViewHolder

If can’t find in the cache, can only call mAdapter) to create new ViewHolder createViewHolder