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;
}
该方法为获取缓存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
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;
}
}
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;
}
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);
}
首先探索何时赋值,我们逆着推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 就是在开始布局前设置缓存,在布局结束后清除缓存。
主要用于屏幕间可见数据的回收和复用。
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);
}
}
// 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);
}
}