总结一下:Recycler就是一个不折不扣的回收站,在里面针对ViewHolder进行一系列回收站应进行的操作。

下一个看adapter类或者rvpool类

// mAttachedScrap是你recycler类中当前维护的废品吗

final ArrayList<ViewHolder>mAttachedScrap = new ArrayList<>();

// mChangedScrap我猜测是将被遣送去重用的viewholder集合

ArrayList<ViewHolder> mChangedScrap =null;

//被缓存的views?

final ArrayList<ViewHolder> mCachedViews= new ArrayList<ViewHolder>();

// 把mAttachedScrap设置成只读(不可修改)的集合,牛

private final List<ViewHolder>

mUnmodifiableAttachedScrap =Collections.unmodifiableList(mAttachedScrap);

//把被请求的缓存最大值和view缓存最大值设为默认值2

private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;

int mViewCacheMax = DEFAULT_CACHE_SIZE;

//维护一个RecycledViewPool的实例

RecycledViewPool mRecyclerPool;

//维护ViewCacheExtension的实例

private ViewCacheExtensionmViewCacheExtension;

static final int DEFAULT_CACHE_SIZE = 2;

//把报废的views从Recycler中清除出去,recyclerview pool中包含着的与recyclerview脱离联系的views将会被留存下来

public void clear() {

mAttachedScrap.clear();

recycleAndClearCachedViews();

}

//设置被分离的、可用的views的最大数量,我们应该为了接下来的使用而保留的

public void setViewCacheSize(int viewCount){

mRequestedCacheMax = viewCount;

updateViewCacheSize();

}

void updateViewCacheSize() {

//更新缓存大小

int extraCache = mLayout != null ? mLayout.mPrefetchMaxCountObserved :0;

mViewCacheMax = mRequestedCacheMax + extraCache;

//这里如果你更新了以后,发现已有的缓存比最大缓存数量大,那么就要把多余的部分回收掉。

// first, try the views that can be recycled

for (int i = mCachedViews.size() - 1;

i >= 0 &&mCachedViews.size() > mViewCacheMax; i--) {

recycleCachedViewAt(i);

}

}

public List<ViewHolder>getScrapList() {

return mUnmodifiableAttachedScrap;

}

//验证ViewHolder的偏移位置(个人感觉神头鬼脸,看不太懂他想用这个方法干什么)

//是getViewForPosition的辅助方法

检查一个被给予的ViewHolder是否可以被用来作为被分享(共享)的位置

booleanvalidateViewHolderForOffsetPosition(ViewHolder holder) {

// if it is a removed holder, nothing to verify since we cannot askadapter anymore

// if it is not removed, verify the type and id.

//如果这个holder已经被移除了,我们不能去校验它因为我们什么都不能询问Adapter了

//如果这个holder没有被移除,校验这个holder的类型和id

if (holder.isRemoved()) {

if (DEBUG &&!mState.isPreLayout()) {

throw newIllegalStateException("should not receive a removed view unless it"

+ " is prelayout");

}

return mState.isPreLayout();

}

if (holder.mPosition < 0 || holder.mPosition >=mAdapter.getItemCount()) {

throw newIndexOutOfBoundsException("Inconsistency detected. Invalid view holder"

+ "adapterposition" + holder);

}

//pre-layout到底是个啥概念?

if (!mState.isPreLayout()) {

// don't check type if it ispre-layout.

final int type =mAdapter.getItemViewType(holder.mPosition);

if (type !=holder.getItemViewType()) {

return false;

}

}

//稳定的id,难道还有不稳定的id?要不要把这么简单的控件写的这么云里雾里?这还是优雅的写法吗?

if (mAdapter.hasStableIds()) {

return holder.getItemId() ==mAdapter.getItemId(holder.mPosition);

}

return true;

}

//试图绑定视图,并考虑相关的时间信息.如果绑定视图的截止期限不等于FOREVER_NS,这个方法或许不能去绑定,并且会返回错误

private booleantryBindViewHolderByDeadline(ViewHolder holder, int offsetPosition,

int position, long deadlineNs){

//哦,不错,在这里把这个recyclerView赋给holder,昨天有看到过

holder.mOwnerRecyclerView = RecyclerView.this;

final int viewType = holder.getItemViewType();

long startBindNs = getNanoTime();//获取java虚拟机中高精度的时间

if (deadlineNs != FOREVER_NS

&&!mRecyclerPool.willBindInTime(viewType, startBindNs, deadlineNs)) {

// abort(退出) - we have a deadline we can't meet

return false;

}

//哦,不错,看到了熟悉的绑定方法,而且参数都是一样的

mAdapter.bindViewHolder(holder, offsetPosition);

long endBindNs = getNanoTime();

//这里是把差值简单记录一下吗

mRecyclerPool.factorInBindTime(holder.getItemViewType(), endBindNs -startBindNs);

//连接可访问性代表?

attachAccessibilityDelegate(holder.itemView);

//这个prelayout还是没能理解

if (mState.isPreLayout()) {

holder.mPreLayoutPosition =position;

}

return true;

}

//绑定所给的view到指定的位置,这个view可以是先前通过getViewForPosition(int)方法被检索的,或者是被Adapter#onCreateViewHolder(ViewGroup, int)方法创建的。大多数情况,一个LayoutManager应该通过getViewForPosition(int)方法来获取他的views并且让recyclerView来处理高速缓存。这是一个辅助方法用于一个想要去处理它自己的回收逻辑的LayoutManager。注意,getViewForPosition(int)方法已经绑定了view到这个位置上所以你不需要去调用这个方法除非你想要去绑定这个view到另一个位置。

public void bindViewToPosition(View view,int position) {

//这个getchild让我,想不穿。

ViewHolder holder = getChildViewHolderInt(view);

if (holder == null) {

throw newIllegalArgumentException("The view does not have a ViewHolder. Youcannot"

+ " pass arbitraryviews to this method, they should be created by the "

+ "Adapter");

}

//竟然还有AdapterHelper和ChildHelper这两个类,我tm。。还有光给一个位置怎么找偏移呢?

final int offsetPosition = mAdapterHelper.findPositionOffset(position);

if (offsetPosition < 0 || offsetPosition >=mAdapter.getItemCount()) {

throw newIndexOutOfBoundsException("Inconsistency detected. Invalid item "

+ "position "+ position + "(offset:" + offsetPosition + ")."

+ "state:" +mState.getItemCount());

}

//看名字来说这个方法就是预处理一下?错了,就是在这个方法中发生了绑定

tryBindViewHolderByDeadline(holder, offsetPosition, position,FOREVER_NS);

//向下转型

final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();

final LayoutParams rvLayoutParams;

if (lp == null) {

rvLayoutParams = (LayoutParams)generateDefaultLayoutParams();

holder.itemView.setLayoutParams(rvLayoutParams);

//如果这个参数未被检查(?)过

} else if (!checkLayoutParams(lp)) {

rvLayoutParams = (LayoutParams)generateLayoutParams(lp);

holder.itemView.setLayoutParams(rvLayoutParams);

} else {

rvLayoutParams = (LayoutParams)lp;

}

//一开始我想,布局参数里还能维护这些实例的?神魔恋?一看,果然又是他自定义的布局参数类

//设置成脏item(?)

rvLayoutParams.mInsetsDirty = true;

//把holder交给他去维护

rvLayoutParams.mViewHolder = holder;

//等待校验中

rvLayoutParams.mPendingInvalidate = holder.itemView.getParent() == null;

}

//转换预布局成布局后

//rv提供人工的位置范围在prelayout状态(终于领悟到了是还未布局的状态),并且自动的把这些位置映射到Adapter的位置当getViewForPosition(int)方法或者bindViewToPosition(View, int)被调用。通常,LayoutManager不需要去忧虑这个问题。然而,在某些情况下,你的LayoutManager或许需要去调用一些自定义组件,其中包含项目位置,在这种情况下你需要实际的Adapter的位置而不是prelayout的位置。你可以使用这个方法去转换一个prelayout的位置成Adapter的位置。注意如果被分享的位置属于一个被删除的ViewHolder,这个方法将会返回-1。调用这个方法在布局后状态将返回相同的值。

public intconvertPreLayoutPositionToPostLayout(int position) {

if (position < 0 || position >= mState.getItemCount()) {

throw newIndexOutOfBoundsException("invalid position " + position + ".State "

+ "item count is" + mState.getItemCount());

}

if (!mState.isPreLayout()) {

return position;

}

return mAdapterHelper.findPositionOffset(position);

}

//获得为给定位置初始化的视图。这个方法应该被LayoutManager的实现类使用,并以此获得views去代表来自Adapter的数据。Recycler可能会重复使用一个报废的或者被脱离联系的View从一个被共享的pool中如果这个是可用的对于正确的view类型。如果适配器没有指出在给定位置的数据已经改变了,这个Recycler将会试图去返回之前为该数据初始化的废料视图,而不是重新绑定。

public View getViewForPosition(intposition) {

return getViewForPosition(position, false);

}

View getViewForPosition(int position,boolean dryRun) {

return tryGetViewHolderForPositionByDeadline(position, dryRun,FOREVER_NS).itemView;

}

//试图从给定的位置去获取ViewHolder,无论是从Recycler的废品,缓存,RecyclerViewPool或者直接的创建

如果在FOREVER_NS之外的截止日期被传递,那么这个方法会尽早返回而不是构建或绑定ViewHolder如果它不认为有这么宽裕的时间。如果必须构造一个ViewHolder并且没有足够的时间,将返回null,如果一个ViewHolder已经被获得(绑定?)并且必须被绑定但是剩下的时间不够了,一个没有被绑定的holder被返回。使用ViewHolder#isBound()方法在被返回的对象去为这个检查。

@Nullable

ViewHolder tryGetViewHolderForPositionByDeadline(int position,

boolean dryRun, longdeadlineNs) {

if (position < 0 || position >= mState.getItemCount()) {

throw newIndexOutOfBoundsException("Invalid item position " + position

+ "(" +position + "). Item count:" + mState.getItemCount());

}

boolean fromScrapOrHiddenOrCache = false;

ViewHolder holder = null;

//如果有一个被改变的废品(又是你,被改变的废品),试图去从那里找到它

// 0) If there is a changed scrap, try to find from there

//又是你,预布局状态

if (mState.isPreLayout()) {

holder =getChangedScrapViewForPosition(position);

//holder只要不为空,就是这三种来源之一(吗?)

fromScrapOrHiddenOrCache =holder != null;

}

//通过废品/被隐藏 集合/缓存找到位置

// 1) Find by position from scrap/hidden list/cache

if (holder == null) {

//取得holder

holder =getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);

//取出来发现不为空

if (holder != null) {

//验证不通过(反正这是一种不能用的状态)

if(!validateViewHolderForOffsetPosition(holder)) {

// recycle holder (andunscrap if relevant) since it can't be used

if (!dryRun) {

//我们想要去回收它但是需要去确认它是否没被使用

// we would like torecycle this but need to make sure it is not used by

//动画逻辑(反正我没太看出来)

// animation logicetc.

holder.addFlags(ViewHolder.FLAG_INVALID);

if(holder.isScrap()) {

removeDetachedView(holder.itemView,false);

holder.unScrap();

} else if(holder.wasReturnedFromScrap()) {

holder.clearReturnedFromScrapFlag();

}

recycleViewHolderInternal(holder);

}

holder = null;

} else {

fromScrapOrHiddenOrCache = true;

}

}

}

if (holder == null) {

//现在领悟到了偏移量还是可以由AdapterHelper求出来的,具体位置还是得由viewholder中记录

final int offsetPosition =mAdapterHelper.findPositionOffset(position);

if (offsetPosition < 0 ||offsetPosition >= mAdapter.getItemCount()) {

throw newIndexOutOfBoundsException("Inconsistency detected. Invalid item "

+ "position" + position + "(offset:" + offsetPosition + ")."

+"state:" + mState.getItemCount());

}

//这里又不懂了啊,你用个偏移量你到底要求是那个item的type啊

final int type =mAdapter.getItemViewType(offsetPosition);

//stable可能是不变的意思了,而不是稳定

// 2) Find from scrap/cache viastable ids, if exists

if (mAdapter.hasStableIds()) {

holder =getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition),

type, dryRun);

if (holder != null) {

// update position

holder.mPosition =offsetPosition;

fromScrapOrHiddenOrCache = true;

}

}

//Extension扩大或者延期的意思

if (holder == null &&mViewCacheExtension != null) {

//我们不是在发送偏移量(还是偏移后的位置)因为LayoutManager不知道这个offsetPosition,后面就是判断了一波异常

// We are NOT sending theoffsetPosition because LayoutManager does not

// know it.

final View view =mViewCacheExtension

.getViewForPositionAndType(this, position, type);

if (view != null) {

holder = getChildViewHolder(view);

if (holder == null) {

throw newIllegalArgumentException("getViewForPositionAndType returned"

+ " aview which does not have a ViewHolder");

} else if(holder.shouldIgnore()) {

throw newIllegalArgumentException("getViewForPositionAndType returned"

+ " aview that is ignored. You must call stopIgnoring before"

+ "returning this view.");

}

}

}

if (holder == null) { //fallback to pool//倒退回rv池中

if (DEBUG) {

Log.d(TAG,"tryGetViewHolderForPositionByDeadline("

+ position +") fetching from shared pool");

}

//取得rv池,通过type取得rv,然后返回一个holder对象(?)

holder =getRecycledViewPool().getRecycledView(type);

if (holder != null) {

//内部重置

holder.resetInternal();

//强制废止display list(干嘛要废止他?)

if(FORCE_INVALIDATE_DISPLAY_LIST) {

//原来是只废掉一个item

invalidateDisplayListInt(holder);

}

}

}

if (holder == null) {

long start = getNanoTime();

if (deadlineNs !=FOREVER_NS

&&!mRecyclerPool.willCreateInTime(type, start, deadlineNs)) {

// abort - we have a deadlinewe can't meet

return null;

}

//哇,又碰到老熟人了,不过少了一个on

holder =mAdapter.createViewHolder(RecyclerView.this, type);

//如果允许 线程间隙工作(可以更详细点吗)

if (ALLOW_THREAD_GAP_WORK){

//只干扰寻找嵌套的rv如果预先取

// only bother finding nested RV ifprefetching

RecyclerView innerView= findNestedRecyclerView(holder.itemView);

if (innerView != null){

//把它转化为弱引用,维护在holder中

holder.mNestedRecyclerView = newWeakReference<>(innerView);

}

}

long end = getNanoTime();

// factorInCreateTime方法到底啥意思

mRecyclerPool.factorInCreateTime(type,end - start);

if (DEBUG) {

Log.d(TAG,"tryGetViewHolderForPositionByDeadline created new ViewHolder");

}

}

}

//连接可访问的代表(?)

private void attachAccessibilityDelegate(ViewitemView) {

//如果可访问

if (isAccessibilityEnabled()) {

//如果view的访问权限是:自动

if(ViewCompat.getImportantForAccessibility(itemView) ==

ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {

//设为YES,可访问

ViewCompat.setImportantForAccessibility(itemView,

ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);

}

//如果返回的是false

if(!ViewCompat.hasAccessibilityDelegate(itemView)) {

ViewCompat.setAccessibilityDelegate(itemView,

//从当前维护的AccessibilityDelegate中取出代表来(?what?why?how)

mAccessibilityDelegate.getItemDelegate());

}

}

}

//废止displaylistint

private voidinvalidateDisplayListInt(ViewHolder holder) {

//如果是viewgroup的实例?理论上是view啊,哪里进行了这个转换?可能是其他地方把它转了,怕这里仍然是一个viewgroup的状态,需要这样操作来规避

if (holder.itemView instanceof ViewGroup) {

invalidateDisplayListInt((ViewGroup) holder.itemView, false);

}

}

private voidinvalidateDisplayListInt(ViewGroup viewGroup, boolean invalidateThis) {

for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) {

final View view =viewGroup.getChildAt(i);

//这里有点巧妙的啊,虽然view比你viewgroup高一级,但是他不管你,因为他只看你继承的是谁,接口是谁。原来是这样啊。哪怕你向上转型了都没用。

if (view instanceof ViewGroup){

//递归调用这个方法。但是这次第二个参数是true。

invalidateDisplayListInt((ViewGroup) view, true);

}

}

//只接受为true的,想把它废止掉

if (!invalidateThis) {

return;

}

//我们需要强制使他不可见,但是你这样设一下取消一下,玩呢?

// we need to force it to become invisible

if (viewGroup.getVisibility() == View.INVISIBLE) {

viewGroup.setVisibility(View.VISIBLE);

viewGroup.setVisibility(View.INVISIBLE);

} else {

final int visibility =viewGroup.getVisibility();

viewGroup.setVisibility(View.INVISIBLE);

viewGroup.setVisibility(visibility);

}

}

public void recycleView(View view) {

//是令view可以回收的方法。尝试去使得view可回收,因为layout manager(?)

// This public recycle method tries to make view recycle-able sincelayout manager

//打算去回收这个view,即使这个view目前是废品或者改变,的缓存中

// intended to recycle this view (e.g. even if it is in scrap or changecache)

//从view中取得这个子holder,还是不太懂

ViewHolder holder = getChildViewHolderInt(view);

//这个tmp不是缓存,难道是临时的意思,临时被脱离联系?

if (holder.isTmpDetached()) {

removeDetachedView(view,false);

}

//让holder从废品堆中脱离,然后是直接显示在界面上还是。。。

if (holder.isScrap()) {

holder.unScrap();

} else if (holder.wasReturnedFromScrap()){

holder.clearReturnedFromScrapFlag();

}

recycleViewHolderInternal(holder);

}

//内部使用这个方法代替recyclerView这个方法去捕捉潜藏的bug

void recycleViewInternal(View view) {

recycleViewHolderInternal(getChildViewHolderInt(view));

}

//回收并且清除缓存的视图

void recycleAndClearCachedViews() {

final int count = mCachedViews.size();

for (int i = count - 1; i >= 0; i--) {

recycleCachedViewAt(i);

}

mCachedViews.clear();

//这个间隙工作感觉是提升稳定性的东西。

if (ALLOW_THREAD_GAP_WORK) {

mPrefetchRegistry.clearPrefetchPositions();

}

}

void recycleCachedViewAt(intcachedViewIndex) {

if (DEBUG) {

Log.d(TAG, "Recyclingcached view at index " + cachedViewIndex);

}

ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);

if (DEBUG) {

Log.d(TAG,"CachedViewHolder to be recycled: " + viewHolder);

}

addViewHolderToRecycledViewPool(viewHolder, true);

mCachedViews.remove(cachedViewIndex);

}

//回收缓存视图并从列表中删除视图。视图被添加到缓存当且仅当它们是可回收的,所以这种方法不会再检查它。这个规则的一个小例外是view没有动画引用(总结一下,没有动画引用的时候,我认为就是可回收的时候)但transient态是true的,那么就相当于不可回收了。在那种情况下,Adapter或许会选择去回收它。从RV的角度来看,这个view仍然是可回收的因为Adapter下你给要这么做。那岂不是很危险!所以我们这个方法的一部分任务是剔除transient属性的view?然而并没有。

void recycleCachedViewAt(intcachedViewIndex) {

if (DEBUG) {

Log.d(TAG, "Recyclingcached view at index " + cachedViewIndex);

}

ViewHolder viewHolder = mCachedViews.get(cachedViewIndex);

if (DEBUG) {

Log.d(TAG,"CachedViewHolder to be recycled: " + viewHolder);

}

addViewHolderToRecycledViewPool(viewHolder, true);

mCachedViews.remove(cachedViewIndex);

}

//内部实现检查是否这个view是报废的或者脱离的并且如果真是这样的话,就抛出异常。

公共版本在调用回收之前取消废弃

void recycleViewHolderInternal(ViewHolderholder) {

//如果这个holder是处于废弃状态的或者item的view还有父viewgroup存在

if (holder.isScrap() || holder.itemView.getParent() != null) {

throw newIllegalArgumentException(

"Scrapped orattached views may not be recycled. isScrap:"

+holder.isScrap() + " isAttached:"

+(holder.itemView.getParent() != null));

}

//如果holder是暂时(?)脱离的状态

if (holder.isTmpDetached()) {

throw newIllegalArgumentException("Tmp detached view should be removed "

+ "from RecyclerViewbefore it can be recycled: " + holder);

}

//如果holder处于应该忽略的状态

if (holder.shouldIgnore()) {

throw newIllegalArgumentException("Trying to recycle an ignored view holder.You"

+ " should first callstopIgnoringView(view) before calling recycle.");

}

//没有检查

//noinspection unchecked

// doesTransientStatePreventRecycling()是否transient状态躲过了盘查

final boolean transientStatePreventsRecycling = holder

.doesTransientStatePreventRecycling();

//如果adapter不为空,transient状态的holder躲过了盘查,且holder不能被回收,那就强制回收

final boolean forceRecycle = mAdapter != null

&& transientStatePreventsRecycling

&&mAdapter.onFailedToRecycleView(holder);

boolean cached = false;

boolean recycled = false;

if (DEBUG && mCachedViews.contains(holder)) {

throw new IllegalArgumentException("cachedview received recycle internal? " +

holder);

}

//如果强制回收 或者holder是可回收的

if (forceRecycle || holder.isRecyclable()) {

if (mViewCacheMax > 0

&& !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID

|ViewHolder.FLAG_REMOVED

|ViewHolder.FLAG_UPDATE

|ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {

//使得最老的缓存view退休。内存的先进先出原则。

// Retire oldest cachedview

int cachedViewSize =mCachedViews.size();

if (cachedViewSize >=mViewCacheMax && cachedViewSize > 0) {

recycleCachedViewAt(0);//清除队列底部的。这tm到底是队列还是栈啊

cachedViewSize--;

}

int targetCacheIndex =cachedViewSize;

/// ALLOW_THREAD_GAP_WORK好想搞懂他,实在憋不住去看了一下:在L +上,使用RenderThread,UI线程在关闭帧之后有空闲时间RenderThread,但在下一帧开始之前。 我们在这个窗口中安排预取工作。(意思就是:在5.0版本以后,多了一个UI的附加线程RenderThread。我们使用这个RenderThread,UI线程在关闭帧之后,在下一帧开始之前有空闲时间。我们再这个窗口中安排预取工作)

if (ALLOW_THREAD_GAP_WORK

&&cachedViewSize > 0

&&!mPrefetchRegistry.lastPrefetchIncludedPosition(holder.mPosition)) {

//添加视图时,跳过最近预取的视图

// when adding theview, skip past most recently prefetched views

int cacheIndex =cachedViewSize - 1;

while (cacheIndex >= 0){

//取得最后一个

int cachedPos =mCachedViews.get(cacheIndex).mPosition;

if

//这个判断花里胡哨,看英文意思一下子看不懂

(!mPrefetchRegistry.lastPrefetchIncludedPosition(cachedPos)){

break;

}

cacheIndex--;

}

targetCacheIndex =cacheIndex + 1;

}

mCachedViews.add(targetCacheIndex,holder);

cached = true;

}

if (!cached) {

addViewHolderToRecycledViewPool(holder, true);

recycled = true;

}

} else {

//注意:当一个view被滚动执行滚动动画的时候,不能被回收。在这种情况,这个item最终被回收通过ItemAnimatorRestoreListener#onAnimationFinished.考虑取消一个动画当一个item被以滚动的形式移动,快速地去返回它到rv池中。

// NOTE: A view can fail to berecycled when it is scrolled off while an animation

// runs. In this case, the itemis eventually recycled by

//ItemAnimatorRestoreListener#onAnimationFinished.

// TODO: consider cancelling ananimation when an item is removed scrollBy,

// to return it to the poolfaster

if (DEBUG) {

Log.d(TAG, "trying torecycle a non-recycleable holder. Hopefully, it will "

+ "re-visithere. We are still removing it from animation lists");

}

}

//即使holder没有被移动,我们仍然调用这个方法以至于这个viewholder从viewholder集合中被移动出来。

// even if the holder is not removed, we still call this method so thatit is removed

// from view holder lists.

mViewInfoStore.removeViewHolder(holder);

if (!cached && !recycled &&transientStatePreventsRecycling) {

holder.mOwnerRecyclerView =null;

}

}

//准备将ViewHolder移除/回收,并将其插入到RecycledViewPool中。将false传递给dispatchRecycled以获得未绑定的视图。

voidaddViewHolderToRecycledViewPool(ViewHolder holder, boolean dispatchRecycled) {

//清除嵌套的rv如果不是嵌套的(?)

clearNestedRecyclerViewIfNotNested(holder);

//得好好研究ViewCompat这个类

ViewCompat.setAccessibilityDelegate(holder.itemView, null);

if (dispatchRecycled) {

dispatchViewRecycled(holder);

}

holder.mOwnerRecyclerView = null;

getRecycledViewPool().putRecycledView(holder);

}

//在批量操作过程中,这个方法用作快速打包和回收视图的路径。当它完成更新回收站的内部簿记,调用者必须调用clearScrap()方法。

void quickRecycleScrapView(View view) {

final ViewHolder holder = getChildViewHolderInt(view);

holder.mScrapContainer = null;

holder.mInChangeScrap = false;

holder.clearReturnedFromScrapFlag();

recycleViewHolderInternal(holder);

}

//把一个建立联系的view标记成废品。废品views是仍然与他们的父母RecyclerView建立联系,但有资格用于重新绑定和重用。要求一个view用于一个被给予的位置或许返回一个重用或者重新绑定的view实例。

void scrapView(View view) {

final ViewHolder holder = getChildViewHolderInt(view);

if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED |ViewHolder.FLAG_INVALID)

|| !holder.isUpdated() ||canReuseUpdatedViewHolder(holder)) {

//如果holder正在被使用,且没有被移除,且Adapter有稳定id

if (holder.isInvalid()&& !holder.isRemoved() && !mAdapter.hasStableIds()){

throw newIllegalArgumentException("Called scrap view with an invalid view."

+ " Invalidviews cannot be reused from scrap, they should rebound from"

+ " recyclerpool.");

}

//把当前recycler设置到holder中维护起来

holder.setScrapContainer(this,false);

mAttachedScrap.add(holder);

} else {

if (mChangedScrap == null) {

mChangedScrap = newArrayList<ViewHolder>();

}

holder.setScrapContainer(this,true);

mChangedScrap.add(holder);

}

}

//从rv池合适的废品中移除一个先前被报废的view。这个view不再是合适的对于重用直到重新被报废,或者他被明确地移除和回收。

void unscrapView(ViewHolder holder) {

if (holder.mInChangeScrap) {

mChangedScrap.remove(holder);

} else {

mAttachedScrap.remove(holder);

}

holder.mScrapContainer = null;

holder.mInChangeScrap = false;

holder.clearReturnedFromScrapFlag();

}

int getScrapCount() {

return mAttachedScrap.size();

}

View getScrapViewAt(int index) {

return mAttachedScrap.get(index).itemView;

}

void clearScrap() {

mAttachedScrap.clear();

if (mChangedScrap != null) {

mChangedScrap.clear();

}

}

//取得被改变的废品的位置

ViewHoldergetChangedScrapViewForPosition(int position) {

//如果处于预布局(?)状态,检查被改变的废品对于一个明确的匹配(?)

// If pre-layout, check the changed scrap for an exact match.

final int changedScrapSize;

if (mChangedScrap == null || (changedScrapSize = mChangedScrap.size())== 0) {

return null;

}

//通过位置来找到holder

// find by position

for (int i = 0; i < changedScrapSize; i++) {

final ViewHolder holder =mChangedScrap.get(i);

if(!holder.wasReturnedFromScrap() && holder.getLayoutPosition() ==position) {

holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);

return holder;

}

}

//通过id来找holder

// find by id

if (mAdapter.hasStableIds()) {

final int offsetPosition =mAdapterHelper.findPositionOffset(position);

if (offsetPosition > 0&& offsetPosition < mAdapter.getItemCount()) {

final long id =mAdapter.getItemId(offsetPosition);

for (int i = 0; i <changedScrapSize; i++) {

final ViewHolderholder = mChangedScrap.get(i);

if(!holder.wasReturnedFromScrap() && holder.getItemId() == id) {

holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);

return holder;

}

}

}

}

return null;

}

//取得holder通过位置,holder的要求:报废的,被隐藏,缓存的

ViewHoldergetScrapOrHiddenOrCachedHolderForPosition(int position, boolean dryRun) {

final int scrapCount = mAttachedScrap.size();

// Try first for an exact, non-invalid match from scrap.

for (int i = 0; i < scrapCount; i++) {

final ViewHolder holder =mAttachedScrap.get(i);

if(!holder.wasReturnedFromScrap() && holder.getLayoutPosition() ==position

&&!holder.isInvalid() && (mState.mInPreLayout || !holder.isRemoved())) {

holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);

return holder;

}

}

if (!dryRun) {

View view = mChildHelper.findHiddenNonRemovedView(position);

if (view != null) {

// This View is good to beused. We just need to unhide, detach and move to the

// scrap list.

final ViewHolder vh =getChildViewHolderInt(view);

mChildHelper.unhide(view);

int layoutIndex =mChildHelper.indexOfChild(view);

if (layoutIndex ==RecyclerView.NO_POSITION) {

throw newIllegalStateException("layout index should not be -1 after "

+"unhiding a view:" + vh);

}

mChildHelper.detachViewFromParent(layoutIndex);

scrapView(view);

vh.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP

|ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST);

return vh;

}

}

// Search in our first-level recycled view cache.

final int cacheSize = mCachedViews.size();

for (int i = 0; i < cacheSize; i++) {

final ViewHolder holder =mCachedViews.get(i);

// invalid view holders may bein cache if adapter has stable ids as they can be

// retrieved viagetScrapOrCachedViewForId

if (!holder.isInvalid()&& holder.getLayoutPosition() == position) {

if (!dryRun) {

mCachedViews.remove(i);

}

if (DEBUG) {

Log.d(TAG,"getScrapOrHiddenOrCachedHolderForPosition(" + position

+ ") foundmatch in cache: " + holder);

}

return holder;

}

}

return null;

}

//取得报废的或者缓存的view通过id

ViewHolder getScrapOrCachedViewForId(longid, int type, boolean dryRun) {

// Look in our attached views first

final int count = mAttachedScrap.size();

for (int i = count - 1; i >= 0; i--) {

final ViewHolder holder =mAttachedScrap.get(i);

if (holder.getItemId() == id&& !holder.wasReturnedFromScrap()) {

if (type ==holder.getItemViewType()) {

holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP);

if (holder.isRemoved()){

// this might bevalid in two cases:

// > itemis removed but we are in pre-layout pass

// >> donothing. return as is. make sure we don't rebind

// > item isremoved then added to another position and we are in

// post layout.

// >> removeremoved and invalid flags, add update flag to rebind

// because item wasinvisible to us and we don't know what happened in

// between.

if(!mState.isPreLayout()) {

holder.setFlags(ViewHolder.FLAG_UPDATE, ViewHolder.FLAG_UPDATE |

ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED);

}

}

return holder;

} else if (!dryRun) {

// if we are runninganimations, it is actually better to keep it in scrap

// but this would force layoutmanager to lay it out which would be bad.

// Recycle this scrap.Type mismatch.

mAttachedScrap.remove(i);

removeDetachedView(holder.itemView, false);

quickRecycleScrapView(holder.itemView);

}

}

}

// Search the first-level cache

final int cacheSize = mCachedViews.size();

for (int i = cacheSize - 1; i >= 0; i--) {

final ViewHolder holder =mCachedViews.get(i);

if (holder.getItemId() == id) {

if (type ==holder.getItemViewType()) {

if (!dryRun) {

mCachedViews.remove(i);

}

return holder;

} else if (!dryRun) {

recycleCachedViewAt(i);

return null;

}

}

}

return null;

}

//当Adapter改变的时候

void onAdapterChanged(Adapter oldAdapter,Adapter newAdapter,

boolean compatibleWithPrevious){

clear();

getRecycledViewPool().onAdapterChanged(oldAdapter, newAdapter,compatibleWithPrevious);

}

//偏移的位置记录为了移动

void offsetPositionRecordsForMove(int from,int to) {

final int start, end, inBetweenOffset;

if (from < to) {

start = from;

end = to;

inBetweenOffset = -1;

} else {

start = to;

end = from;

inBetweenOffset = 1;

}

final int cachedCount = mCachedViews.size();

for (int i = 0; i < cachedCount; i++) {

final ViewHolder holder =mCachedViews.get(i);

if (holder == null ||holder.mPosition < start || holder.mPosition > end) {

continue;

}

if (holder.mPosition == from) {

holder.offsetPosition(to -from, false);

} else {

holder.offsetPosition(inBetweenOffset, false);

}

if (DEBUG) {

Log.d(TAG,"offsetPositionRecordsForMove cached child " + i + " holder" +

holder);

}

}

}

void offsetPositionRecordsForInsert(intinsertedAt, int count) {

final int cachedCount =mCachedViews.size();

for (int i = 0; i < cachedCount; i++) {

final ViewHolder holder =mCachedViews.get(i);

if (holder != null &&holder.mPosition >= insertedAt) {

if (DEBUG) {

Log.d(TAG,"offsetPositionRecordsForInsert cached " + i + " holder " +

holder + "now at position " + (holder.mPosition + count));

}

holder.offsetPosition(count, true);

}

}

}

//如果最后一个参数是true的话,改变将会影响ViewHolder的预布局位置,如果false,他们将会被应用在第二个布局传递来之前

void offsetPositionRecordsForRemove(intremovedFrom, int count, boolean applyToPreLayout) {

final int removedEnd = removedFrom + count;

final int cachedCount = mCachedViews.size();

for (int i = cachedCount - 1; i >= 0; i--) {

final ViewHolder holder =mCachedViews.get(i);

if (holder != null) {

if (holder.mPosition >=removedEnd) {

if (DEBUG) {

Log.d(TAG,"offsetPositionRecordsForRemove cached " + i +

"holder " + holder + " now at position " +

(holder.mPosition - count));

}

holder.offsetPosition(-count, applyToPreLayout);

} else if (holder.mPosition>= removedFrom) {

// Item for this viewwas removed. Dump it from the cache.

holder.addFlags(ViewHolder.FLAG_REMOVED);

recycleCachedViewAt(i);

}

}

}

}

voidsetViewCacheExtension(ViewCacheExtension extension) {

mViewCacheExtension = extension;

}

void setRecycledViewPool(RecycledViewPoolpool) {

if (mRecyclerPool != null) {

mRecyclerPool.detach();

}

mRecyclerPool = pool;

if (pool != null) {

mRecyclerPool.attach(getAdapter());

}

}

RecycledViewPool getRecycledViewPool() {

if (mRecyclerPool == null) {

mRecyclerPool = newRecycledViewPool();

}

return mRecyclerPool;

}

//视图区域更新

void viewRangeUpdate(int positionStart, intitemCount) {

final int positionEnd = positionStart + itemCount;

final int cachedCount = mCachedViews.size();

for (int i = cachedCount - 1; i >= 0; i--) {

final ViewHolder holder =mCachedViews.get(i);

if (holder == null) {

continue;

}

final int pos =holder.mPosition;

if (pos >= positionStart&& pos < positionEnd) {

holder.addFlags(ViewHolder.FLAG_UPDATE);

recycleCachedViewAt(i);

// cached views should notbe flagged as changed because this will cause them

// to animate when they arereturned from cache.

}

}

}

void setAdapterPositionsAsUnknown() {

final int cachedCount = mCachedViews.size();

for (int i = 0; i < cachedCount; i++) {

final ViewHolder holder =mCachedViews.get(i);

if (holder != null) {

holder.addFlags(ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);

}

}

}

//标记已知的view无效

void markKnownViewsInvalid() {

if (mAdapter != null &&mAdapter.hasStableIds()) {

final int cachedCount =mCachedViews.size();

for (int i = 0; i <cachedCount; i++) {

final ViewHolder holder =mCachedViews.get(i);

if (holder != null) {

holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID);

holder.addChangePayload(null);

}

}

} else {

// we cannot re-use cachedviews in this case. Recycle them all

recycleAndClearCachedViews();

}

}

void clearOldPositions() {

final int cachedCount = mCachedViews.size();

for (int i = 0; i < cachedCount; i++) {

final ViewHolder holder =mCachedViews.get(i);

holder.clearOldPosition();

}

final int scrapCount = mAttachedScrap.size();

for (int i = 0; i < scrapCount; i++) {

mAttachedScrap.get(i).clearOldPosition();

}

if (mChangedScrap != null) {

final int changedScrapCount =mChangedScrap.size();

for (int i = 0; i <changedScrapCount; i++) {

mChangedScrap.get(i).clearOldPosition();

}

}

}

void markItemDecorInsetsDirty() {

final int cachedCount = mCachedViews.size();

for (int i = 0; i < cachedCount; i++) {

final ViewHolder holder =mCachedViews.get(i);

LayoutParams layoutParams =(LayoutParams) holder.itemView.getLayoutParams();

if (layoutParams != null) {

layoutParams.mInsetsDirty =true;

}

}

}

Android——RecyclerView——Recycler类全部源码翻译及注释相关推荐

  1. android类中定义颜色,自定义实现简单的Android颜色选择器(附带源码)

    在写Android App过程中需要一个简单的颜色选择器,Android自带的ColorPicker和网上的一些ColorPicker都太高端了,都实现了颜色渐变功能,我要的不需要那么复杂,只想提供几 ...

  2. Android 网络框架之Retrofit源码解析,flutter边框特效

    Retrofit的构建使用了建造者模式,这个模式的优点就是可以构造复杂的对象,方便扩展,并且看起来代码比较简洁,美观: 在开始之前,我们先来看一下Retrofit的成员变量: 这里的变量并不是很多,我 ...

  3. android+高仿+日历,项目源码--Android天气日历精致UI源码

    技术要点: 1. 天气日历精致UI 2. Android的Http通信技术 3. Android的天气信息解析 4. Android的日历信息的统计 5. Andorid的地理位置的管理 6.源码带有 ...

  4. Android Jetpack 组件之 Lifecycle源码

    1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...

  5. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  6. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  7. 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | Instrumentation 源码分析 )

    文章目录 一.Instrumentation 源码分析 二.Instrumentation 创建 Application 相关的部分源码 dex 解密时 , 需要将 代理 Application 替换 ...

  8. 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | LoadedApk 源码分析 )

    文章目录 一.LoadedApk 源码分析 二.LoadedApk 源码 makeApplication 方法分析 dex 解密时 , 需要将 代理 Application 替换为 真实 Applic ...

  9. Android的Handler,Looper源码剖析

    之前了解android的消息处理机制,但是源码看的少,现在把Looper,Handler,Message这几个类的源码分析一哈 android的消息处理有三个核心类:Looper,Handler和Me ...

最新文章

  1. 前端(移动端)开发利器Chrome Developer Tools秘籍(下)
  2. Transformer结构详解(有图,有细节)
  3. socket 相关函数
  4. 一天一种设计模式之六-----工厂方法模式
  5. ubuntu设置代理 的三种方式
  6. 【数据结构与算法】图
  7. flume学习-含安装
  8. dateframe取某列数据_Python获取时序数据并进行可视化分析
  9. Rtworld防洪系统全解开源完整源码
  10. 使用Postman测试https接口时的小问题记录
  11. [原创]java WEB学习笔记107:Spring学习---AOP切面的优先级,重用切点表达式
  12. 电脑遇到脱机状态怎么解除?
  13. python语法学习第十天--类与对象
  14. paip.账务系统的安全性
  15. I2C(smbus pmbus)和SPI分析
  16. 解决SpringBoot项目jar包启动慢
  17. matlab trapz二重积分函数_matlab数值微积分
  18. c语言if语句教学设计,if语句教学设计
  19. C#获取http请求的JSON数据并解析
  20. 机械之美——机械时期的计算设备

热门文章

  1. 英语英文理论驾考宝典 驾照考试题库软件
  2. 传真百科:电子传真邮件客户端
  3. 前端框架 ng 环境配置
  4. 【docker入门】
  5. Lenovo windows 解决win键失灵
  6. 让电脑死机c语言,秘技:如何悄无声息的让一台电脑死机
  7. Android 面部识别之二(调用开源面部识别算法seetaface检测)
  8. GB2312转unicode
  9. 用计算机弹奏体面6,抖音计算器乐谱汇总 抖音计算器按出的音乐乐谱有哪些
  10. android 输入法更换_详解安卓手机输入法和键盘切换方式的教程