本文参考自:【进阶】RecyclerView源码解析(二)——缓存机制 https://www.jianshu.com/p/e44961f8add5
---起因:由notifyItemRemoved引起的刷新,ui缓冲,加载holder。
- 管理缓存的内部类:
public final class Recycler { * 1.一级缓存:mAttachedScrap * 2.二级缓存:mCacheViews * 3.三级缓存:mViewCacheExtension (自定义缓存) * 4.四级缓存:mRecyclerPool final ArrayList<RecyclerView.ViewHolder> mAttachedScrap = new ArrayList(); ArrayList<RecyclerView.ViewHolder> mChangedScrap = null; final ArrayList<RecyclerView.ViewHolder> mCachedViews = new ArrayList(); RecyclerView.RecycledViewPool mRecyclerPool; }
- recyclerview缓存holder的大致步骤
- 缓存入口 :
final View view = recycler.getViewForPosition(mCurrentPosition);
-
View getViewForPosition(int position, boolean dryRun) { return this.tryGetViewHolderForPositionByDeadline(position, dryRun, 9223372036854775807L).itemView; } RecyclerView.ViewHolder tryGetViewHolderForPositionByDeadline(int position, boolean dryRun, long deadlineNs) { .......... 1. 默认为false,只有有动画的时候为true , holder 从Recycler类 mChangeScrap 中获取 但是这个 并不在 正常的四级缓存中,,因为大多数时候都是false。 if (RecyclerView.this.mState.isPreLayout()) { holder = this.getChangedScrapViewForPosition(position); fromScrapOrHiddenOrCache = holder != null; } 2.第一次正式获取缓存 //看名字 就知道 分三步 scrap hidden cache holder = this.getScrapOrHiddenOrCachedHolderForPosition(position, dryRun); RecyclerView.ViewHolder getScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) { **尝试从一级缓存mAttachedScrap 获取缓存 for(cacheSize = 0; cacheSize < scrapCount; ++cacheSize) { vh = (RecyclerView.ViewHolder)this.mAttachedScrap.get(cacheSize); ...... } ** 。。。。有个hiddenView if (!dryRun) { //从HiddenView中获得,这里获得是View View view = mChildHelper.findHiddenNonRemovedView(position); if (view != null) { final ViewHolder vh = getChildViewHolderInt(view); //添加到scrap中? scrapView(view); } } **尝试从二级缓存获取 final int cacheSize = mCachedViews.size(); for (int i = 0; i < cacheSize; i++) { final ViewHolder holder = mCachedViews.get(i); //holder是有效的,并且position相同 if (!holder.isInvalid() && holder.getLayoutPosition() == position) { if (!dryRun) { mCachedViews.remove(i); } return holder; } } }
2.第二次正式获取缓存 //从scrap cache 通过 id 获取
if (holder == null) {
.....
type = RecyclerView.this.mAdapter.getItemViewType(offsetPosition);
if (RecyclerView.this.mAdapter.hasStableIds()) {
holder = this.getScrapOrCachedViewForId(RecyclerView.this.mAdapter.getItemId(offsetPosition), type, dryRun);
...
}
RecyclerView.ViewHolder getScrapOrCachedViewForId(long id, int type, boolean dryRun) {
*** 尝试从一级缓存attachedScrap 获取
for(i = count - 1; i >= 0; --i) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder)this.mAttachedScrap.get(i);
if (type == holder.getItemViewType()) {
holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);
.....
if (!dryRun) {
this.mAttachedScrap.remove(i);
.....
}
}
***尝试从二级缓存cacheView获取
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);
}
}
}
- 第三次正式获取缓存 (自定义缓存 ,e)
- 第四次正式获取缓存 ----是完全的针对pool 的 和之前的 性质不一样
holder = this.getRecycledViewPool().getRecycledView(type);
public static class RecycledViewPool {
private static final int DEFAULT_MAX_SCRAP = 5;
static class ScrapData {
ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
int mMaxScrap = DEFAULT_MAX_SCRAP;
....
}
SparseArray<ScrapData> mScrap = new SparseArray<>();
...
// 可以看到 SparseArray 的 key 是ViewType, value 是 ArrayList<ViewHolder>。
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;
}
......
}
- 第五次“获取”缓存 ----当以上4步都没有得到 缓存的holder,通过自己创建holder
holder = RecyclerView.this.mAdapter.createViewHolder(RecyclerView.this, type);