总结一下:Recycler就是一个不折不扣的回收站,在里面针对ViewHolder进行一系列回收站应进行的操作。
下一个看adapter类或者rvpool类
// mAttachedScrap是你recycler类中当前维护的废品吗
final ArrayList
// mChangedScrap我猜测是将被遣送去重用的viewholder集合
ArrayList
//被缓存的views?
final ArrayList
// 把mAttachedScrap设置成只读(不可修改)的集合,牛
private final List
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
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
}
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 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 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 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; } } }