一、緩存
二、緩存 mCachedViews
執行LinearLayoutManager.onLayoutChildren
方法
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
...
detachAndScrapAttachedViews(recycler);
...
}
public void detachAndScrapAttachedViews(@NonNull Recycler recycler) {
final int childCount = getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
final View v = getChildAt(i);
scrapOrRecycleView(recycler, i, v);
}
}
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()) {
//將index的view從mHiddenViews移除的動作
removeViewAt(index);
//向 mCachedViews 或 Pool 中添加
recycler.recycleViewHolderInternal(viewHolder);
} else {
//設置RecyclerView這個位置的view的parent爲null, 並標記ViewHolder爲FLAG_TMP_DETACHED
detachViewAt(index);
//添加到mAttachedScrap 或 mCachedViews集合中
recycler.scrapView(view);
mRecyclerView.mViewInfoStore.onViewDetached(viewHolder);
}
}
然後在RecyclerView
的集合中緩存
2.1、 mCachedViews 或 Pool 緩存
void recycleViewHolderInternal(RecyclerView.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(RecyclerView.ViewHolder.FLAG_INVALID
| RecyclerView.ViewHolder.FLAG_REMOVED
| RecyclerView.ViewHolder.FLAG_UPDATE
| RecyclerView.ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {
// Retire oldest cached view
int cachedViewSize = mCachedViews.size();
//大於緩存的最大值 mViewCacheMax = 2, CacheView 把老的移除集合,放入 pool 中
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
//取出集合的第一個元素放入 pool 中
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 集合
mCachedViews.add(targetCacheIndex, holder);
cached = true;
}
if (!cached) {
// 添加到Pool中
addViewHolderToRecycledViewPool(holder, true);
recycled = true;
}
} else {
if (DEBUG) {
Log.d(TAG, "trying to recycle a non-recycleable holder. Hopefully, it will "
+ "re-visit here. We are still removing it from animation lists"
+ exceptionLabel());
}
}
mViewInfoStore.removeViewHolder(holder);
if (!cached && !recycled && transientStatePreventsRecycling) {
holder.mOwnerRecyclerView = null;
}
}
- 接下來看向 pool 中添加的步驟
void addViewHolderToRecycledViewPool(@NonNull RecyclerView.ViewHolder holder, boolean dispatchRecycled) {
clearNestedRecyclerViewIfNotNested(holder);
View itemView = holder.itemView;
if (mAccessibilityDelegate != null) {
AccessibilityDelegateCompat itemDelegate = mAccessibilityDelegate.getItemDelegate();
AccessibilityDelegateCompat originalDelegate = null;
if (itemDelegate instanceof RecyclerViewAccessibilityDelegate.ItemDelegate) {
originalDelegate =
((RecyclerViewAccessibilityDelegate.ItemDelegate) itemDelegate)
.getAndRemoveOriginalDelegateForItem(itemView);
}
// Set the a11y delegate back to whatever the original delegate was.
ViewCompat.setAccessibilityDelegate(itemView, originalDelegate);
}
if (dispatchRecycled) {
dispatchViewRecycled(holder);
}
holder.mOwnerRecyclerView = null;
getRecycledViewPool().putRecycledView(holder);
}
public void putRecycledView(RecyclerView.ViewHolder scrap) {
final int viewType = scrap.getItemViewType();
final ArrayList<RecyclerView.ViewHolder> scrapHeap = getScrapDataForType(viewType).mScrapHeap;
if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) {
return;
}
if (DEBUG && scrapHeap.contains(scrap)) {
throw new IllegalArgumentException("this scrap item already exists");
}
scrap.resetInternal();
scrapHeap.add(scrap);
}
調用RecyclerView.RecycledViewPool
中的方法getScrapDataForType
private ScrapData getScrapDataForType(int viewType) {
ScrapData scrapData = mScrap.get(viewType);
if (scrapData == null) {
scrapData = new ScrapData();
mScrap.put(viewType, scrapData);
}
return scrapData;
}
2.2、mAttachedScrap 或 mCachedViews 緩存
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("Called scrap view with an invalid view."
+ " Invalid views cannot be reused from scrap, they should rebound from"
+ " recycler pool." + exceptionLabel());
}
holder.setScrapContainer(this, false);
mAttachedScrap.add(holder);
} else {
if (mChangedScrap == null) {
mChangedScrap = new ArrayList<ViewHolder>();
}
holder.setScrapContainer(this, true);
mChangedScrap.add(holder);
}
}