RecyclerView Recycling and Reuse
I was asked this question during an interview a while ago, but unfortunately I only know that Recycler view can reduce the optimization of creating views by recycling and reusing views when I use them.How is it cached inside a single cell?How much is cached?How do I distinguish between different views?
Take advantage of this week's leisure to solve this problem, there is no password under the source code, then we start from the source code!
View Recycle
/**
* Delete subviews and recycle using the given recycling mechanism
*/
public void removeAndRecycleView(View child, Recycler recycler) {
removeView(child);
recycler.recycleView(child);
}
This is the entry we want to study. It's very simple. The first line deletes the subview, the second line recycles the view, and we follow the second line of code.
public void recycleView(View view) {
// This public recycle method tries to make view recycle-able since layout manager
// intended to recycle this view (e.g. even if it is in scrap or change cache)
ViewHolder holder = getChildViewHolderInt(view);
if (holder.isTmpDetached()) {
removeDetachedView(view, false);
}
if (holder.isScrap()) {
holder.unScrap();
} else if (holder.wasReturnedFromScrap()) {
holder.clearReturnedFromScrapFlag();
}
recycleViewHolderInternal(holder);
}
This code mainly makes some judgments, not the part we need to focus on. We call recyclerViewHolderInternal on the last line and follow up.
This method has a lot of code, so we intercept the middle piece of code that interests us.
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0)
int mViewCacheMax = DEFAULT_CACHE_SIZE
static final int DEFAULT_CACHE_SIZE = 2
As you can see here, instead of an unused View being immediately recycled, it is first stored in the mCachedViews, which recycles the View at position 0 when the mCachedViews is greater than 2.
/**
* Recycle cached views from list(mCachedViews)Delete in
*/
void recycleCachedViewAt(int cachedViewIndex) {
ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);
addViewHolderToRecycledViewPool(viewHolder, true);
mCachedViews.remove(cachedViewIndex);
}
It is more important in the * addViewHolderToRecycledViewPool * method to get the * RecycledViewPool * object and add the incoming viewHolder to it.
public void putRecycledView(ViewHolder scrap) {
final int viewType = scrap.getItemViewType();
final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap;
if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {
return;
}
scrap.resetInternal();
scrapHeap.add(scrap);
}
This, along with some scrap code, makes sense
static class ScrapData {
ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
int mMaxScrap = DEFAULT_MAX_SCRAP;
long mCreateRunningAverageNs = 0;
long mBindRunningAverageNs = 0;
}
SparseArray<ScrapData> mScrap = new SparseArray<>();
You can see that when you recycle Views, they are stored in different ScrapData s by ViewType, and the maximum default number of caches is 5.
SparseArray is equivalent to HashMap
Reuse of View
View reuse can start with the getViewForPosition method, focusing on the tryGetViewHolderForPositionByDeadline method, which is a very long method and we intercept important parts.
You can see that we use RecycledViewPool to get the holder of the cache from the viewType
/**
* Return to cache and delete
*/
public ViewHolder getRecycledView(int viewType) {
final ScrapData scrapData = mScrap.get(viewType);
if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) {
final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
return scrapHeap.remove(scrapHeap.size() - 1);
}
return null;
}
The process of reusing Views is relatively understandable, that is, using ViewType to obtain cached views in RecycledViewPool.
Other
During this learning process, you also noticed that it was nice to share views among multiple RecyclerViews by setting RecycledViewPool for RecyclerView.For example, some wait for View, wrong View, but ViewType must be handled properly.