https://github.com/samwangds/AndroidInterview
public final class Recycler {
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
ArrayList<ViewHolder> mChangedScrap = null;
final ArrayList<ViewHolder> mCachedViews = new ArrayList<>();
RecycledViewPool mRecyclerPool;
private ViewCacheExtension mViewCacheExtension;
}
一级缓存:mAttachedScrap 和 mChangedScrap ,用来缓存还在屏幕内的 ViewHolder
/*
* Note that, Recycler never sends Views to this method to be cached. It is developers
* responsibility to decide whether they want to keep their Views in this custom cache or let
* the default recycling policy handle it.
*/
public abstract static class ViewCacheExtension {
public abstract View getViewForPositionAndType(...);
}
RecyclerView.onLayout(...)
-> RecyclerView.dispatchLayout()
-> RecyclerView.dispatchLayoutStep2() // do the actual layout of the views for the final state.
-> mLayout.onLayoutChildren(mRecycler, mState) // mLayout 类型为 LayoutManager
-> LinearLayoutManager.onLayoutChildren(...) // 以 LinearLayoutManager 为例
-> LinearLayoutManager.fill(...) // The magic functions :) 填充给定的布局,注释很自信的说这个方法很独立,稍微改动就能作为帮助类的一个公开方法,程序员的快乐就是这么朴实无华。
-> LinearLayoutManager.layoutChunk(recycler, layoutState) // 循环调用,每次调用填充一个 ItemView 到 RV
-> LinearLayoutManager.LayoutState.next(recycler)
-> RecyclerView.Recycler.getViewForPosition(int) // 回到主角了,通过 Recycler 获取指定位置的 ItemView
-> Recycler.getViewForPosition(int, boolean) // 调用下面方法获取 ViewHolder,并返回上面需要的 viewHolder.itemView
-> Recycler.tryGetViewHolderForPositionByDeadline(...) // 终于找到你,还好没放弃~
ViewHolder tryGetViewHolderForPositionByDeadline(int position, ...) {
if (mState.isPreLayout()) {
// 0) 预布局从 mChangedScrap 里面去获取 ViewHolder,动画相关
holder = getChangedScrapViewForPosition(position);
}
if (holder == null) {
// 1) 分别从 mAttachedScrap、 mHiddenViews、mCachedViews 获取 ViewHolder
// 这个 mHiddenViews 是用来做动画期间的复用
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
}
if (holder == null) {
final int type = mAdapter.getItemViewType(offsetPosition);
// 2) 如果 Adapter 的 hasStableIds 方法返回为 true
// 优先通过 ViewType 和 ItemId 两个条件从 mAttachedScrap 和 mCachedViews 寻找
if (mAdapter.hasStableIds()) {
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
}
if (holder == null && mViewCacheExtension != null) {
// We are NOT sending the offsetPosition because LayoutManager does not know it.
// 3) 从自定义缓存获取,别问,问就是别用
View view = mViewCacheExtension
getViewForPositionAndType(this, position, type);
holder = getChildViewHolder(view);
}
}
if (holder == null) {
// 4) 从 RecycledViewPool 获取 ViewHolder
holder = getRecycledViewPool().getRecycledView(type);
}
if (holder == null) {
// 缓存全取过了,没有,那只好 create 一个咯
holder = mAdapter.createViewHolder(RecyclerView.this, type);
}
// This is very ugly but the only place we can grab this information
// 大半夜看到这句注释的时候笑出声!像极了我写出丑代码时的无奈。
// 在这后面有一些刷新 ViewHolder 信息的代码,放这很丑,但又只能放这; 为了能走到这,前面有多少 if (holder == null)
}
// 调用链
LinearLayoutManager.onLayoutChildren(...)
-> LayoutManager.detachAndScrapAttachedViews(recycler)
-> LayoutManager.scrapOrRecycleView(..., view)
-> Recycler.scrapView(view);
private void scrapOrRecycleView(Recycler recycler, int index, View view) {
final ViewHolder viewHolder = getChildViewHolderInt(view);
if (viewHolder.isInvalid() && !viewHolder.isRemoved()
&& !mRecyclerView.mAdapter.hasStableIds()) {
// 后面会讲,缓存到 mCacheViews 和 RecyclerViewPool
recycler.recycleViewHolderInternal(viewHolder);
} else {
// 缓存到 scrap
recycler.scrapView(view);
}
}
void scrapView(View view) {
final ViewHolder holder = getChildViewHolderInt(view);
if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
|| !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) {
// 标记为移除或失效的 || 完全没有改变 || item 无动画或动画不复用
mAttachedScrap.add(holder);
} else {
// 相反就得出放入 mChangedScrap 的条件啦
mChangedScrap.add(holder);
}
}
Recycler.tryGetViewHolderForPositionByDeadline(...)
-> Recycler.getScrapOrHiddenOrCachedHolderForPosition(...)
-> Recycler.scrapView(view)
void recycleViewHolderInternal(ViewHolder holder) {
if (forceRecycle || holder.isRecyclable()) {
if(mViewCacheMax > 0
&& !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
| ViewHolder.FLAG_REMOVED
| ViewHolder.FLAG_UPDATE
| ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {
int cachedViewSize = mCachedViews.size();
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
// 1. mCacheViews 满了,最早加入的不要了放 RecyclerViewPool
recycleCachedViewAt(0);
}
mCachedViews.add(targetCacheIndex, holder);
cached = true;
}
if (!cached) {
// 2. 不能放进 mCacheViews 的放 RecyclerViewPool
addViewHolderToRecycledViewPool(holder, true);
}
}
}
// Recycles a cached view and removes the view from the list
void recycleCachedViewAt(int cachedViewIndex) {
ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);
addViewHolderToRecycledViewPool(viewHolder, true);
mCachedViews.remove(cachedViewIndex);
}