如下所示,注释1处表示又会调用recycleViewHolderInternal;
public void recycleView(@NonNull View view) {
、、、
recycleViewHolderInternal(holder); //1
}
6-1 RecyclerView # Recycler
在分析recycleViewHolderInternal方法之前,我们先简单分析一下RecyclerView的两个内部类Recycler类和RecyclerViewPool;
RecyclerView # Recycler
Recycler如下所示,注释1和注释2是一级缓存,其实就是泛型为ViewHolder的ArrayList;注释3就是二级缓存,注释4处的mViewCacheMax表示二级缓存的最大容量为2;注释5就是四级缓存RecycledViewPool;注释6就是第三级缓存,也就是自定义缓存;
public final class Recycler {
final ArrayList mAttachedScrap = new ArrayList<>(); //1
ArrayList mChangedScrap = null; //2
final ArrayList mCachedViews = new ArrayList(); //3
private final List
mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
int mViewCacheMax = DEFAULT_CACHE_SIZE; //4
RecycledViewPool mRecyclerPool; //5
private ViewCacheExtension mViewCacheExtension; //6
static final int DEFAULT_CACHE_SIZE = 2; //7
、、、
}
RecyclerView # RecycledViewPool
RecycledViewPool如下所示,先看注释2处的内部类ScrapData,注释3处的mScrapHeap就是缓存ViewHolder的ArrayList,注释4处表示最大容量为5,即可以缓存ViewHolder的个数为5;注释5处mScrap是一个SparseArray,其泛型为内部类ScrapData,这表示什么意思呢?就是说RecyclerViewPool对每种类型的ViewHolder最大缓存个数为5,然后可以缓存多种ViewHolder类型;
public static class RecycledViewPool {
private static final int DEFAULT_MAX_SCRAP = 5; //1
static class ScrapData { //2
final ArrayList mScrapHeap = new ArrayList<>(); //3
int mMaxScrap = DEFAULT_MAX_SCRAP; //4
long mCreateRunningAverageNs = 0;
long mBindRunningAverageNs = 0;
}
SparseArray mScrap = new SparseArray<>(); //5
、、、
}
6-2 Recycler -> recycleViewHolderInternal
在recycleViewHolderInternal方法中才是执行真正的回收操作,主要是使用第二级缓存mCachedViews和第四级缓存RecyclerViewPool;注释1、2处表示mCachedViews容量满了之后会调用recycleCachedViewAt方法,然后将size–;注释3处表示往mCachedViews添加;注释4表示往缓存池添加;
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)) {
// Retire oldest cached view
int cachedViewSize = mCachedViews.size();
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
recycleCachedViewAt(0); //1
cachedViewSize–; //2
}
、、、
mCachedViews.add(targetCacheIndex, holder); //3
cached = true;
}
if (!cached) {
addViewHolderToRecycledViewPool(holder, true); //4
recycled = true;
}
}
}
7、Recycler -> recycleCachedViewAt
recycleCachedViewAt如下所示,注释1、2表示将mCachedViews的viewHolder移除,然后添加到RecycledViewPool;
void recycleCachedViewAt(int cachedViewIndex) {
if (DEBUG) {
Log.d(TAG, "Recycling cached view at index " + cachedViewIndex);
}
ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);
if (DEBUG) {
Log.d(TAG, "CachedViewHolder to be recycled: " + viewHolder);
}
addViewHolderToRecycledViewPool(viewHolder, true); //1
mCachedViews.remove(cachedViewIndex); //2
}
8、Recycler -> addViewHolderToRecycledViewPool
如下所示,注释1表示将ViewHolder添加到RecyclerViewPool;到此回收完毕;
void addViewHolderToRecycledViewPool(@NonNull ViewHolder holder, boolean dispatchRecycled) {
、、、
getRecycledViewPool().putRecycledView(holder); //1
}
1、LinearLayoutManager -> layoutChunk
接着第一部分的layoutChunk方法分析复用部分,如下所示,注释1表示又会调用LayoutState的next方法;
void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
LayoutState layoutState, LayoutChunkResult result) {
View view = layoutState.next(recycler); //1
、、、
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
if (layoutState.mScrapList == null) {
if (mShouldReverseLayout == (layoutState.mLayoutDirection
== LayoutState.LAYOUT_START)) {
addView(view);
} else {
addView(view, 0);
}
}
、、、
}
2、LayoutState -> next
next方法如下所示,注释1又调用了getViewForPosition方法;
View next(RecyclerView.Recycler recycler) {
if (mScrapList != null) {
return nextViewFromScrapList();
}
final View view = recycler.getViewForPosition(mCurrentPosition); //1
mCurrentPosition += mItemDirection;
return view;
}
3、Recycler -> getViewForPosition
getViewForPosition方法如下所示,注释1又会调用到注释2;
public View getViewForPosition(int position) {
return getViewForPosition(position, false); //1
}
View getViewForPosition(int position, boolean dryRun) {
return tryGetViewHolderForPositionByDeadline(position, dryRun, FOREVER_NS).itemView; //2
}
4、Recycler -> tryGetViewHolderForPositionByDeadline
tryGetViewHolderForPositionByDeadline方法就是真正去寻找缓存进行复用了,这个方法比较长,这里只截取主要部分的代码,如下所示;
注释1处表示从mChangedScrap中寻找;
注释2和注释3表示从mAttachedScrap和mCachedView中去寻找;
注释4表示从自定义缓存中去寻找;
注释5表示从RecyclerViewPool中去寻找;
注释6表示如果上边所有的缓存都没有的话,就调用我们重写的Adapter的onCreateViewHolder去创建;
注释7处表示获取到ViewHolder之后再去调用Adapter的onBindViewHolder进行数据绑定,所以现在我们应该明白为什么要在我们重写的Adapter中重写这两个方法了;
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
boolean dryRun, long deadlineNs) {
、、、
ViewHolder holder = null;
// 0) If there is a changed scrap, try to find from there
if (mState.isPreLayout()) {
holder = getChangedScrapViewForPosition(position); //1
fromScrapOrHiddenOrCache = holder != null;
}
// 1) Find by position from scrap/hidden list/cache
if (holder == null) {
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun); //2
、、、
}
if (holder == null) {
、、、
// 2) Find from scrap/cache via stable ids, if exists
if (mAdapter.hasStableIds()) {
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),
type, dryRun); //3
}
if (holder == null && mViewCacheExtension != null) {
// We are NOT sending the offsetPosition because LayoutManager does not
// know it.
final View view = mViewCacheExtension
.getViewForPositionAndType(this, position, type); //4
、、、
}
if (holder == null) { // fallback to pool
holder = getRecycledViewPool().getRecycledView(type); //5
、、、
}
if (holder == null) {
、、、
holder = mAdapter.createViewHolder(RecyclerView.this, type); //6
、、、
}
}
、、、
boolean bound = false;
if (mState.isPreLayout() && holder.isBound()) {
// do not update unless we absolutely have to.
holder.mPreLayoutPosition = position;
} else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
、、、
bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);//7
}
、、、
return holder;
}
1、RecyclerView -> onLayout
前面三个部分我们是从onTouchEvent方法的MOVE分支中切入讨论的,这一部分我们从RecyclerView的布局方法onLayout方法切入分析;
protected void onLayout(boolean changed, int l, int t, int r, int b) {
TraceCompat.beginSection(TRACE_ON_LAYOUT_TAG);
dispatchLayout(); //1
TraceCompat.endSection();
mFirstLayoutComplete = true;
}
2、RecyclerView -> dispatchLayout
如下所示,可以看到RecyclerView的dispatchLayout方法中主要分为三步;这里分析一下注释2的第二步;
void dispatchLayout() {
、、、
mState.mIsMeasuring = false;
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1(); //1
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2(); //2
} else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth()
|| mLayout.getHeight() != getHeight()) {
// First 2 steps are done in onMeasure but looks like we have to run again due to
// changed size.
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2();
} else {
// always make sure we sync them (to ensure mode is exact)
mLayout.setExactMeasureSpecsFrom(this);
}
dispatchLayoutStep3(); //3
}
3、LinearLayoutManager -> onLayoutChildren
onLayoutChildren方法比较长,如下我们只看关键部分,注释1处又会调用removeAndRecycleViewAt;注释3、4处的fill方法正是我们前面重点讨论的方法;我们这里重点看一下注释2;
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
、、、
if (mPendingSavedState != null || mPendingScrollPosition != RecyclerView.NO_POSITION) {
if (state.getItemCount() == 0) {
removeAndRecycleAllViews(recycler); //1
return;
}
}
、、、
detachAndScrapAttachedViews(recycler); //2
、、、
if (mAnchorInfo.mLayoutFromEnd) {
// fill towards start
updateLayoutStateToFillStart(mAnchorInfo);
mLayoutState.mExtraFillSpace = extraForStart;
fill(recycler, mLayoutState, state, false); //3
startOffset = mLayoutState.mOffset;
final int firstElement = mLayoutState.mCurrentPosition;
if (mLayoutState.mAvailable > 0) {
extraForEnd += mLayoutState.mAvailable;
}
// fill towards end
updateLayoutStateToFillEnd(mAnchorInfo);
mLayoutState.mExtraFillSpace = extraForEnd;
mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
fill(recycler, mLayoutState, state, false); //4
}
、、、
}
4、LayoutManager -> detachAndScrapAttachedViews
如下所示,又会调用scrapOrRecycleView
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); //1
}
}
5、LayoutManager -> scrapOrRecycleView
scrapOrRecycleView如下所示,注释1表示又会调用Recycler的scrapView
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数同学面临毕业设计项目选题时,很多人都会感到无从下手,尤其是对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。
因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!
由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频
如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
leView(recycler, i, v); //1
}
}
5、LayoutManager -> scrapOrRecycleView
scrapOrRecycleView如下所示,注释1表示又会调用Recycler的scrapView
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数同学面临毕业设计项目选题时,很多人都会感到无从下手,尤其是对于计算机专业的学生来说,选择一个合适的题目尤为重要。因为毕业设计不仅是我们在大学四年学习的一个总结,更是展示自己能力的重要机会。
因此收集整理了一份《2024年计算机毕业设计项目大全》,初衷也很简单,就是希望能够帮助提高效率,同时减轻大家的负担。
[外链图片转存中…(img-wt7JSwOb-1712511860130)]
[外链图片转存中…(img-JMsY9DUf-1712511860131)]
[外链图片转存中…(img-5MKcBXuf-1712511860132)]
既有Java、Web、PHP、也有C、小程序、Python等项目供你选择,真正体系化!
由于项目比较多,这里只是将部分目录截图出来,每个节点里面都包含素材文档、项目源码、讲解视频
如果你觉得这些内容对你有帮助,可以添加VX:vip1024c (备注项目大全获取)
[外链图片转存中…(img-rA3IGfJC-1712511860132)]