Recycler組成
RecyclerView的緩存主要委託給了Recycler,先了解下組成
public final class Recycler {
final ArrayList<RecyclerView.ViewHolder> mAttachedScrap = new ArrayList();
ArrayList<RecyclerView.ViewHolder> mChangedScrap = null;
final ArrayList<RecyclerView.ViewHolder> mCachedViews = new ArrayList();
private final List<RecyclerView.ViewHolder> mUnmodifiableAttachedScrap;
private int mRequestedCacheMax;
int mViewCacheMax;
RecyclerView.RecycledViewPool mRecyclerPool;
private RecyclerView.ViewCacheExtension mViewCacheExtension;
static final int DEFAULT_CACHE_SIZE = 2;
//...
}
* 1.一級緩存:mAttachedScrap
* 2.二級緩存:mCacheViews
* 3.三級緩存:mViewCacheExtension
* 4.四級緩存:mRecyclerPool
在RecyclerView的繪製流程中分析過,layoutManager會在layoutChunk方法中對view進行獲取添加測量等操作,如下所示
//LinerLayoutManager.java
void layoutChunk(Recycler recycler, State state, LinearLayoutManager.LayoutState layoutState, LinearLayoutManager.LayoutChunkResult result) {
View view = layoutState.next(recycler);
// 執行addView
// 測量view
}
//LinearLayoutManager.LayoutState
View next(Recycler recycler) {
// mScrapList初始化爲空,且僅在layoutForPredictiveAnimations被賦值,執行完後又被設置爲null
if (this.mScrapList != null) {
return this.nextViewFromScrapList();
} else {
// * 進入該分支
View view = recycler.getViewForPosition(this.mCurrentPosition);
this.mCurrentPosition += this.mItemDirection;
return view;
}
}
//RecyclerView.Recycler
@NonNull
public View getViewForPosition(int position) {
return this.getViewForPosition(position, false);
}
View getViewForPosition(int position, boolean dryRun) {
return this.tryGetViewHolderForPositionByDeadline(position, dryRun, 9223372036854775807L).itemView;
}
tryGetViewHolderForPositionByDeadline
該方法爲獲取緩存viewHolder核心方法
//RecyclerView.Recycler
@Nullable
RecyclerView.ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) {
if (position >= 0 && position < RecyclerView.this.mState.getItemCount()) {
boolean fromScrapOrHiddenOrCache = false;
RecyclerView.ViewHolder holder = null;
//[0] 從changed Scrap獲取holder
if (RecyclerView.this.mState.isPreLayout()) {
//preLayout默認是false,只有有動畫的時候才爲true?
holder = this.getChangedScrapViewForPosition(position);
fromScrapOrHiddenOrCache = holder != null;
}
//[1] 從scrap中獲取holder
if (holder == null) {
holder = this.getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
if (holder != null) {
// 檢查該holder是否與holder對應postion
if (!this.validateViewHolderForOffsetPosition(holder)) {
// 如果信息不符
if (!dryRun) {
holder.addFlags(4);
// 從scrap移除
if (holder.isScrap()) {
RecyclerView.this.removeDetachedView(holder.itemView, false);
holder.unScrap();
} else if (holder.wasReturnedFromScrap()) {
holder.clearReturnedFromScrapFlag();
}
// 將該holder放入mCachedViews或者mRecyclerPool中
this.recycleViewHolderInternal(holder);
}
//設置爲空
holder = null;
} else {
fromScrapOrHiddenOrCache = true;
}
}
}
int offsetPosition;
int type;
if (holder == null) {
offsetPosition = RecyclerView.this.mAdapterHelper.findPositionOffset(position);
if (offsetPosition < 0 || offsetPosition >= RecyclerView.this.mAdapter.getItemCount()) {
throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item position " + position + "(offset:" + offsetPosition + ")." + "state:" + RecyclerView.this.mState.getItemCount() + RecyclerView.this.exceptionLabel());
}
type = RecyclerView.this.mAdapter.getItemViewType(offsetPosition);
if (RecyclerView.this.mAdapter.hasStableIds()) {
holder = this.getScrapOrCachedViewForId(RecyclerView.this.mAdapter.getItemId(offsetPosition), type, dryRun);
if (holder != null) {
holder.mPosition = offsetPosition;
fromScrapOrHiddenOrCache = true;
}
}
// 自定義緩存
if (holder == null && this.mViewCacheExtension != null) {
View view = this.mViewCacheExtension.getViewForPositionAndType(this, position, type);
if (view != null) {
holder = RecyclerView.this.getChildViewHolder(view);
if (holder == null) {
throw new IllegalArgumentException("getViewForPositionAndType returned a view which does not have a ViewHolder" + RecyclerView.this.exceptionLabel());
}
if (holder.shouldIgnore()) {
throw new IllegalArgumentException("getViewForPositionAndType returned a view that is ignored. You must call stopIgnoring before returning this view." + RecyclerView.this.exceptionLabel());
}
}
}
// 從緩存池中獲取
if (holder == null) {
holder = this.getRecycledViewPool().getRecycledView(type);
if (holder != null) {
holder.resetInternal();
if (RecyclerView.FORCE_INVALIDATE_DISPLAY_LIST) {
this.invalidateDisplayListInt(holder);
}
}
}
// 創建
if (holder == null) {
long start = RecyclerView.this.getNanoTime();
if (deadlineNs != 9223372036854775807L && !this.mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
return null;
}
holder = RecyclerView.this.mAdapter.createViewHolder(RecyclerView.this, type);
if (RecyclerView.ALLOW_THREAD_GAP_WORK) {
RecyclerView innerView = RecyclerView.findNestedRecyclerView(holder.itemView);
if (innerView != null) {
holder.mNestedRecyclerView = new WeakReference(innerView);
}
}
long end = RecyclerView.this.getNanoTime();
this.mRecyclerPool.factorInCreateTime(type, end - start);
}
}
if (RecyclerView.this.mState.isPreLayout() && holder.isBound()) {
holder.mPreLayoutPosition = position;
} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
// 如果ViewHolder是從recyclerPool中拿到的,由於其ViewHolder信息初始化則需要進行bindViewHolder
type = RecyclerView.this.mAdapterHelper.findPositionOffset(position);
bound = this.tryBindViewHolderByDeadline(holder, type, position, deadlineNs);
}
// .......
return holder;
} else {
throw new IndexOutOfBoundsException("Invalid item position " + position + "(" + position + "). Item count:" + RecyclerView.this.mState.getItemCount() + RecyclerView.this.exceptionLabel());
}
}
if (RecyclerView.this.mState.isPreLayout()) {
//preLayout默認是false,只有有動畫的時候才爲true?
holder = this.getChangedScrapViewForPosition(position);
fromScrapOrHiddenOrCache = holder != null;
}
//RecyclerView.State
public boolean isPreLayout() {
return this.mInPreLayout;
}
=> this.mState.mInPreLayout = this.mState.mRunPredictiveAnimations;
=> this.mState.mRunPredictiveAnimations = this.mState.mRunSimpleAnimations && animationTypeSupported && !this.mDataSetHasChangedAfterLayout && this.predictiveItemAnimationsEnabled();
// 唉,索引到這裏我已經暈了,有的博主說當動畫執行的時候爲true
1、依據position從mAttachedScrap/HiddenViews/mCachedViews中獲取holder
if (holder == null) {
holder = this.getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
if (holder != null) {
// 檢驗從scrap貨cache獲取的holder是否與position對應
if (!this.validateViewHolderForOffsetPosition(holder)) {
if (!dryRun) {
holder.addFlags(4);
// 如果信息不符合 scrap中移除該scrap
if (holder.isScrap()) {
RecyclerView.this.removeDetachedView(holder.itemView, false);
holder.unScrap();
} else if (holder.wasReturnedFromScrap()) {
holder.clearReturnedFromScrapFlag();
}
// 將該holder放入mCachedViews或mRecyclerPool
this.recycleViewHolderInternal(holder);
}
holder = null;
} else {
fromScrapOrHiddenOrCache = true;
}
}
}
RecyclerView.ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) {
int scrapCount = this.mAttachedScrap.size();
int cacheSize;
RecyclerView.ViewHolder vh;
// **[1] for循環遍歷mAttachedScrap獲取postion相等的viewHolder
for(cacheSize = 0; cacheSize < scrapCount; ++cacheSize) {
vh = (RecyclerView.ViewHolder)this.mAttachedScrap.get(cacheSize);
if (!vh.wasReturnedFromScrap() && vh.getLayoutPosition() == position && !vh.isInvalid() && (RecyclerView.this.mState.mInPreLayout || !vh.isRemoved())) {
vh.addFlags(32);
return vh;
}
}
// dryRun爲false
if (!dryRun) {
// **[2]從隱藏但沒有移除的view中尋找
// todo 在哪裏進行添加的?
View view = RecyclerView.this.mChildHelper.findHiddenNonRemovedView(position);
if (view != null) {
vh = RecyclerView.getChildViewHolderInt(view);
RecyclerView.this.mChildHelper.unhide(view);
int layoutIndex = RecyclerView.this.mChildHelper.indexOfChild(view);
if (layoutIndex == -1) {
throw new IllegalStateException("layout index should not be -1 after unhiding a view:" + vh + RecyclerView.this.exceptionLabel());
}
RecyclerView.this.mChildHelper.detachViewFromParent(layoutIndex);
// scrap緩存holder
this.scrapView(view);
vh.addFlags(8224);
return vh;
}
}
cacheSize = this.mCachedViews.size();
// ** [3] 從CacheViews中去獲取
for(int i = 0; i < cacheSize; ++i) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)this.mCachedViews.get(i);
if (!holder.isInvalid() && holder.getLayoutPosition() == position) {
if (!dryRun) {
this.mCachedViews.remove(i);
}
return holder;
}
}
return null;
}
type = RecyclerView.this.mAdapter.getItemViewType(offsetPosition);
if (RecyclerView.this.mAdapter.hasStableIds()) {
holder = this.getScrapOrCachedViewForId(RecyclerView.this.mAdapter.getItemId(offsetPosition), type, dryRun);
if (holder != null) {
holder.mPosition = offsetPosition;
fromScrapOrHiddenOrCache = true;
}
}
mHasStableIds在Adapter中默認是false,而修改其值的api如下所示,
當我們在對Adapter設置setHasStableIds(true)時,注意得重寫getItemId
public void setHasStableIds(boolean hasStableIds) {
if (this.hasObservers()) {
throw new IllegalStateException("Cannot change whether this adapter has stable IDs while the adapter has registered observers.");
} else {
this.mHasStableIds = hasStableIds;
}
}
2、依據ID type從mAttachedScrap和CacheView中獲取holder
RecyclerView.ViewHolder getScrapOrCachedViewForId(long id, int type, boolean dryRun) {
int count = this.mAttachedScrap.size();
int i;
// for循環遍歷mAttachedScrap,找出id相等的holder
for(i = count - 1; i >= 0; --i) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)this.mAttachedScrap.get(i);
if (holder.getItemId() == id && !holder.wasReturnedFromScrap()) {
if (type == holder.getItemViewType()) {
holder.addFlags(32);
if (holder.isRemoved() && !RecyclerView.this.mState.isPreLayout()) {
holder.setFlags(2, 14);
}
return holder;
}
if (!dryRun) {
this.mAttachedScrap.remove(i);
RecyclerView.this.removeDetachedView(holder.itemView, false);
this.quickRecycleScrapView(holder.itemView);
}
}
}
// 以ID爲判斷標準從CachedView中尋找holder
i = this.mCachedViews.size();
for(int ix = i - 1; ix >= 0; --ix) {
RecyclerView.ViewHolder holderx = (RecyclerView.ViewHolder)this.mCachedViews.get(ix);
if (holderx.getItemId() == id) {
if (type == holderx.getItemViewType()) {
if (!dryRun) {
this.mCachedViews.remove(ix);
}
return holderx;
}
if (!dryRun) {
this.recycleCachedViewAt(ix);
return null;
}
}
}
return null;
}
3、自定義緩存獲取holder
4、依據type從mRecyclerPool獲取holder
if (holder == null) {
holder = this.getRecycledViewPool().getRecycledView(type);
if (holder != null) {
holder.resetInternal();
if (RecyclerView.FORCE_INVALIDATE_DISPLAY_LIST) {
this.invalidateDisplayListInt(holder);
}
}
}
5、緩存都沒有重新創建
if (holder == null) {
long start = RecyclerView.this.getNanoTime();
if (deadlineNs != 9223372036854775807L && !this.mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {
return null;
}
holder = RecyclerView.this.mAdapter.createViewHolder(RecyclerView.this, type);
if (RecyclerView.ALLOW_THREAD_GAP_WORK) {
RecyclerView innerView = RecyclerView.findNestedRecyclerView(holder.itemView);
if (innerView != null) {
holder.mNestedRecyclerView = new WeakReference(innerView);
}
}
long end = RecyclerView.this.getNanoTime();
this.mRecyclerPool.factorInCreateTime(type, end - start);
}
問題探究
Q1: mAttachedScrap何時緩存列表數據?何時銷燬緩存?
首先探索何時賦值,我們逆着推Recycler中mAttachedScrap何時調用的
mAttachedScrap 緩存holder
// RecyclerView.java
public final class Recycler {
void scrapView(View view) {
....
this.mAttachedScrap.add(holder);
}
}
// RecyclerView.java
public abstract static class LayoutManager {
// .....
private void scrapOrRecycleView(RecyclerView.Recycler recycler, int index, View view) {
RecyclerView.ViewHolder viewHolder = RecyclerView.getChildViewHolderInt(view);
if (!viewHolder.shouldIgnore()) {
if (viewHolder.isInvalid() && !viewHolder.isRemoved() && !this.mRecyclerView.mAdapter.hasStableIds()) {
// layoutManager刪除該項
this.removeViewAt(index);
// 將holder放入cacheView或recyclerViewPool中
recycler.recycleViewHolderInternal(viewHolder);
} else {
this.detachViewAt(index);
// 將view加入mAttchScraps中
recycler.scrapView(view);
this.mRecyclerView.mViewInfoStore.onViewDetached(viewHolder);
}
}
}
=> // scrapOrRecycleView 在該方法中調用
public void detachAndScrapAttachedViews(@NonNull RecyclerView.Recycler recycler) {
// 獲取layout可見的佈局
int childCount = this.getChildCount();
for(int i = childCount - 1; i >= 0; --i) {
View v = this.getChildAt(i);
// 調用
this.scrapOrRecycleView(recycler, i, v);
}
}
}
//LinearlayoutManager.java
public class LinearLayoutManager extends LayoutManager{
public void onLayoutChildren(Recycler recycler, State state) {
// 在fill之前
// 在填充表項之前回收所有表項
this.detachAndScrapAttachedViews(recycler);
//...
this.fill(recycler, this.mLayoutState, state, false);
}
// onLayoutChildren 就是在 dispatchLayoutStep2()進行的調用
}
在將表項一個個填充到列表之前會先將其先回收到mAttachedScrap中,回收數據的來源是LayoutManager的孩子,而LayoutManager的孩子都是屏幕上可見的數據項。
mAttachedScrap用於屏幕中可見數據項的回收和複用
mAttachedScrap 清除緩存
//RecyclerView.java
public final class Recycler{
void clearScrap() {
this.mAttachedScrap.clear();
if (this.mChangedScrap != null) {
this.mChangedScrap.clear();
}
}
}
// RecyclerView.java
public abstract static class LayoutManager {
/**
* Recycles the scrapped views.
* 回收所有scrapped view
*/
void removeAndRecycleScrapInt(Recycler recycler) {
final int scrapCount = recycler.getScrapCount();
// Loop backward, recycler might be changed by removeDetachedView()
//遍歷搜有scrap view並重置ViewHolder狀態
for (int i = scrapCount - 1; i >= 0; i--) {
final View scrap = recycler.getScrapViewAt(i);
final ViewHolder vh = getChildViewHolderInt(scrap);
if (vh.shouldIgnore()) {
continue;
}
vh.setIsRecyclable(false);
if (vh.isTmpDetached()) {
mRecyclerView.removeDetachedView(scrap, false);
}
if (mRecyclerView.mItemAnimator != null) {
mRecyclerView.mItemAnimator.endAnimation(vh);
}
vh.setIsRecyclable(true);
recycler.quickRecycleScrapView(scrap);
}
//清空scrap view集合
recycler.clearScrap();
if (scrapCount > 0) {
mRecyclerView.invalidate();
}
}
}
private void dispatchLayoutStep3() {
//....
this.mLayout.removeAndRecycleScrapInt(this.mRecycler);
//....
}
mAttachedScrap 就是在開始佈局前設置緩存,在佈局結束後清除緩存。
主要用於屏幕間可見數據的回收和複用。
Recycler回收機制
RecyclerView滑動時,當有可用空間時,首先會從緩存或重新創建view,然後進行添加,然後會依據頂部或底部的view是否會滑出屏幕,如果是的話,會進行回收,添加入CacheViews中。
從緩存中獲取view時,如果CachedViews中存在,則會將holder從list中刪除並返回;
如果cacheViews中找不到,則會從RecyclerPool中依據type進行尋找,找到之後還需執行bindViewHolder刷新數據。
// RecyclerView.java
void scrollStep(int dx, int dy, @Nullable int[] consumed) {
//....
if (dy != 0) {
consumedY = this.mLayout.scrollVerticallyBy(dy, this.mRecycler, this.mState);
}
}
//LinearLayoutManager
public int scrollVerticallyBy(int dy, Recycler recycler, State state) {
return this.mOrientation == 0 ? 0 : this.scrollBy(dy, recycler, state);
}
int scrollBy(int dy, Recycler recycler, State state) {
int consumed = this.mLayoutState.mScrollingOffset + this.fill(recycler, this.mLayoutState, state, false);
//...
}
//LinearLayoutManager
int fill(Recycler recycler, LinearLayoutManager.LayoutState layoutState, State state, boolean stopOnFocusable) {
while((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {
layoutChunkResult.resetInternal();
this.layoutChunk(recycler, state, layoutState, layoutChunkResult);
// ....
if (layoutState.mScrollingOffset != -2147483648) {
this.recycleByLayoutState(recycler, layoutState);
}
}
return start - layoutState.mAvailable;
}
//RecyclerView.java
private void recycleByLayoutState(Recycler recycler, LinearLayoutManager.LayoutState layoutState) {
if (layoutState.mRecycle && !layoutState.mInfinite) {
if (layoutState.mLayoutDirection == -1) {
this.recycleViewsFromEnd(recycler, layoutState.mScrollingOffset);
} else {
this.recycleViewsFromStart(recycler, layoutState.mScrollingOffset);
}
}
}
private void recycleViewsFromStart(Recycler recycler, int dt) {
if (dt >= 0) {
int limit = dt;
int childCount = this.getChildCount();
int i;
View child;
if (this.mShouldReverseLayout) {
for(i = childCount - 1; i >= 0; --i) {
child = this.getChildAt(i);
if (this.mOrientationHelper.getDecoratedEnd(child) > limit || this.mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
this.recycleChildren(recycler, childCount - 1, i);
return;
}
}
} else {
for(i = 0; i < childCount; ++i) {
child = this.getChildAt(i);
if (this.mOrientationHelper.getDecoratedEnd(child) > limit || this.mOrientationHelper.getTransformedEndWithDecoration(child) > limit) {
this.recycleChildren(recycler, 0, i);
return;
}
}
}
}
}
private void recycleChildren(Recycler recycler, int startIndex, int endIndex) {
if (startIndex != endIndex) {
int i;
if (endIndex > startIndex) {
for(i = endIndex - 1; i >= startIndex; --i) {
this.removeAndRecycleViewAt(i, recycler);
}
} else {
for(i = startIndex; i > endIndex; --i) {
this.removeAndRecycleViewAt(i, recycler);
}
}
}
}
public void removeAndRecycleViewAt(int index, @NonNull RecyclerView.Recycler recycler) {
View view = this.getChildAt(index);
this.removeViewAt(index);
recycler.recycleView(view);
}
回收滑出屏幕對應的ViewHolder
# RecyclerView.Recycler
public void recycleView(@NonNull View view) {
RecyclerView.ViewHolder holder = RecyclerView.getChildViewHolderInt(view);
if (holder.isTmpDetached()) {
RecyclerView.this.removeDetachedView(view, false);
}
if (holder.isScrap()) {
holder.unScrap();
} else if (holder.wasReturnedFromScrap()) {
holder.clearReturnedFromScrapFlag();
}
this.recycleViewHolderInternal(holder);
}
void recycleViewHolderInternal(RecyclerView.ViewHolder holder) {
// ....
if (forceRecycle || holder.isRecyclable()) {
if (this.mViewCacheMax > 0 && !holder.hasAnyOfTheFlags(526)) {
int cachedViewSize = this.mCachedViews.size();
// 當緩存的數量大於最大緩存數量時,mCachedViews會移除最老的一個view
if (cachedViewSize >= this.mViewCacheMax && cachedViewSize > 0) {
// 移除cacheView中數據
this.recycleCachedViewAt(0);
--cachedViewSize;
}
int targetCacheIndex = cachedViewSize;
if (RecyclerView.ALLOW_THREAD_GAP_WORK && cachedViewSize > 0 && !RecyclerView.this.mPrefetchRegistry.lastPrefetchIncludedPosition(holder.mPosition)) {
int cacheIndex;
for(cacheIndex = cachedViewSize - 1; cacheIndex >= 0; --cacheIndex) {
int cachedPos = ((RecyclerView.ViewHolder)this.mCachedViews.get(cacheIndex)).mPosition;
if (!RecyclerView.this.mPrefetchRegistry.lastPrefetchIncludedPosition(cachedPos)) {
break;
}
}
targetCacheIndex = cacheIndex + 1;
}
// ** 將holder加入mCacheViews中
this.mCachedViews.add(targetCacheIndex, holder);
cached = true;
}
if (!cached) {
// 如果沒有加入mCacheViews則將holder加入RecyclerPool中
this.addViewHolderToRecycledViewPool(holder, true);
recycled = true;
}
}
}
//RecyclerView.java
// 將mCacheViews中ViewHolder放入recyclerPool中
public final class Recycler{
void recycleCachedViewAt(int cachedViewIndex) {
RecyclerView.ViewHolder viewHolder = (RecyclerView.ViewHolder)this.mCachedViews.get(cachedViewIndex);
this.addViewHolderToRecycledViewPool(viewHolder, true);
this.mCachedViews.remove(cachedViewIndex);
}
}
從mCachedViews移除掉的ViewHolder會加入到回收池中。 mCachedViews有點像“回收池預備隊列”,即總是先回收到mCachedViews,當它放不下的時候,按照先進先出原則將最先進入的ViewHolder存入回收池
// RecyclerView.java
public staitic final Recycler{
void addViewHolderToRecycledViewPool(@NonNull RecyclerView.ViewHolder holder, boolean dispatchRecycled) {
if (dispatchRecycled) {
this.dispatchViewRecycled(holder);
}
holder.mOwnerRecyclerView = null;
this.getRecycledViewPool().putRecycledView(holder);
}
// 進行一些回調
void dispatchViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
if (RecyclerView.this.mRecyclerListener != null) {
RecyclerView.this.mRecyclerListener.onViewRecycled(holder);
}
if (RecyclerView.this.mAdapter != null) {
RecyclerView.this.mAdapter.onViewRecycled(holder);
}
if (RecyclerView.this.mState != null) {
RecyclerView.this.mViewInfoStore.removeViewHolder(holder);
}
}
}
// RecyclerView.java
public static class RecycledViewPool {
public void putRecycledView(RecyclerView.ViewHolder scrap) {
int viewType = scrap.getItemViewType();
ArrayList<RecyclerView.ViewHolder> scrapHeap = this.getScrapDataForType(viewType).mScrapHeap;
if (((RecyclerView.RecycledViewPool.ScrapData)this.mScrap.get(viewType)).mMaxScrap > scrapHeap.size()) {
// 在緩存前重置ViewHolder內部信息,包括position,itemID之類
// 這樣下次從recyclerPool中拿出來複用時就可以當一個新的ViewHolder使用
scrap.resetInternal();
scrapHeap.add(scrap);
}
}
void resetInternal() {
this.mFlags = 0;
this.mPosition = -1;
this.mOldPosition = -1;
this.mItemId = -1L;
this.mPreLayoutPosition = -1;
this.mIsRecyclableCount = 0;
this.mShadowedHolder = null;
this.mShadowingHolder = null;
this.clearPayload();
this.mWasImportantForAccessibilityBeforeHidden = 0;
this.mPendingAccessibilityState = -1;
RecyclerView.clearNestedRecyclerViewIfNotNested(this);
}
}
Q: mCachedViews中 mViewCacheMax默認值時是多少?可以修改?如何修改呢?
// RecyclerView.java
public final class Recycler {
public Recycler() {
this.mUnmodifiableAttachedScrap = Collections.unmodifiableList(this.mAttachedScrap);
this.mRequestedCacheMax = 2;
this.mViewCacheMax = 2;
}
public void setViewCacheSize(int viewCount) {
this.mRequestedCacheMax = viewCount;
this.updateViewCacheSize();
}
// 更新緩存的最大數量
void updateViewCacheSize() {
int extraCache = RecyclerView.this.mLayout != null ? RecyclerView.this.mLayout.mPrefetchMaxCountObserved : 0;
// 設置最大緩存數量
this.mViewCacheMax = this.mRequestedCacheMax + extraCache;
for(int i = this.mCachedViews.size() - 1; i >= 0 && this.mCachedViews.size() > this.mViewCacheMax; --i) {
this.recycleCachedViewAt(i);
}
}
}
// RecyclerView.java
public void setItemViewCacheSize(int size) {
this.mRecycler.setViewCacheSize(size);
}
mCacheViews默認緩存的數量是2,我們可通過調用RecyclerView的setItemViewCacheSize來設置Recycler中mCacheViews的最大數量
計算平移的距離,遍歷子view進行平移滑動平移
public void offsetChildrenVertical(@Px int dy) {
int childCount = this.mChildHelper.getChildCount();
for(int i = 0; i < childCount; ++i) {
this.mChildHelper.getChildAt(i).offsetTopAndBottom(dy);
}
}