網(wǎng)上的大多數(shù)博客都是認為RecyclerView是4級緩存,但真的是4級緩存嗎?知道我看了源碼,才發(fā)現(xiàn),RecyclerView做的遠遠不止4級緩存,當然是根據(jù)LayoutManager不同,緩存實現(xiàn)也不同,本文主要分析最最常用的LinearLayoutManager。
寫的有點亂,以后整理吧
RecyclerView復用過程
RecyclerView的中的緩存復用是由內部類Recycler來維護的,在RecyclerView.Adapter調用onCreateViewHolder來創(chuàng)建ViewHolder,這時就開始了利用緩存機制;
這里是以LinearLayoutManager為例,其他也差不多,只是一些細節(jié)不一樣;
先看下調用流程吧,否則直接看緩存,也不知道什么時候調用的:

可以看到,RecyclerView的在onMeasure時,就將item所有的操作都交給了LayoutManager,并在創(chuàng)建ViewHolder時,將緩存復用機制交給了RecyclerView內部類Recycler,Recycler的tryGetViewHolderForPositionByDeadline方法內,實現(xiàn)了所有的復用機制;
緩存實現(xiàn)
Recycler :緩存機制的管理類

public final class Recycler {
//主要由void scrapView(View view)來處理, 仍舊綁定在RecyclerView上,但是能rebinding和reuse;
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
ArrayList<ViewHolder> mChangedScrap = null;
final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
private final List<ViewHolder> mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
RecycledViewPool mRecyclerPool;
private ViewCacheExtension mViewCacheExtension;
}
從代碼里這來看,里面就有4個集合外加一個RecycledViewPool和一個ViewCacheExtension,所以遠不止4級緩存;
緩存的實現(xiàn)
接下來我們詳細看下復用機制的實現(xiàn):
其實在LayoutState的next方法中就有一層復用,mScrapList實際就是mUnmodifiableAttachedScrap,這個調用是在onLayoutChildren最后的layoutForPredictiveAnimations的方法中,做動畫時,直接去拿mUnmodifiableAttachedScrap中的itemView;
否則才是真正的去創(chuàng)建View;
View next(RecyclerView.Recycler recycler) {
if (mScrapList != null) {
return nextViewFromScrapList();
}
final View view = recycler.getViewForPosition(mCurrentPosition);
mCurrentPosition += mItemDirection;
return view;
getViewForPosition中主要調用tryGetViewHolderForPositionByDeadline方法:
ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {
RecyclerView.ViewHolder holder = null;
// 0) If there is a changed scrap, try to find from there
// isPreLayout的條件是在RecyclerView的onMeasure中,如果不是自動測量,adapter大小不是固定的,或者是自定義onMeasure
//如果只是changed,就會進入到getChangedScrapViewForPosition,里面主要從mChangedScrap取數(shù)據(jù);
if (mState.isPreLayout()) {
//里面主要是從mChangedScrap中找
holder = getChangedScrapViewForPosition(position);
}
// 1) Find by position from scrap/hidden list/cache
if (holder == null) {
// 里面主要從mAttachedScrap和ChildHelper的mHiddenViews還有mCachedViews中查找
//這里面是確切的匹配,里面各種狀態(tài)必須完全一致,拿出來的,不需要經過rebinding
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
}
if (holder == null) {
final int offsetPosition = mAdapterHelper.findPositionOffset(position);
final int type = mAdapter.getItemViewType(offsetPosition);
// 2) Find from scrap/cache via stable ids, if exists
//hasStableIds默認是true,在adapter的構造中賦值的
if (mAdapter.hasStableIds()) {
//利用Position找不到時,再用id和type匹配,拿出來之后需要rebinding
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
}
// 用戶自定義擴展緩存
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);
}
}
//RecycledView復用池
if (holder == null) { // fallback to pool
holder = getRecycledViewPool().getRecycledView(type);
}
// 創(chuàng)建新的Item
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);
if (ALLOW_THREAD_GAP_WORK) {
// only bother finding nested RV if prefetching
RecyclerView innerView = findNestedRecyclerView(holder.itemView);
if (innerView != null) {
holder.mNestedRecyclerView = new WeakReference<>(innerView);
}
}
}
}
return holder;
}
在LayoutState中的next方法中還有一層緩存,利用的mScrapList ,其實mScrapList 就是mUnmodifiableAttachedScrap
View next(RecyclerView.Recycler recycler) {
if (mScrapList != null) {
return nextViewFromScrapList();
}
final View view = recycler.getViewForPosition(mCurrentPosition);
mCurrentPosition += mItemDirection;
return view;
}
private View nextViewFromScrapList() {
final int size = mScrapList.size();
for (int i = 0; i < size; i++) {
final View view = mScrapList.get(i).itemView;
final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
if (lp.isItemRemoved()) {
continue;
}
if (mCurrentPosition == lp.getViewLayoutPosition()) {
assignPositionFromScrapList(view);
return view;
}
}
return null;
}
這里面涉及到2個緩存mAttachedScrap和mChangedScrap,可以看到這2個緩存的定義了
void scrapView(View view) {
final ViewHolder holder = getChildViewHolderInt(view);
if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
|| !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {
if (holder.isInvalid() && !holder.isRemoved() && !mAdapter.hasStableIds()) {
throw new IllegalArgumentException(...);
}
holder.setScrapContainer(this, false);
mAttachedScrap.add(holder);
} else {
if (mChangedScrap == null) {
mChangedScrap = new ArrayList<ViewHolder>();
}
holder.setScrapContainer(this, true);
mChangedScrap.add(holder);
}
}
總結
寫的有些亂,代碼太多了,都很重要,建議自己再看一遍
