Android——RecyclerView——Recycler类全部源码翻译及注释

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


下一个看adapter类或者rvpool类

 

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

final ArrayListmAttachedScrap = new ArrayList<>();

 

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

ArrayList mChangedScrap =null;

 

//被缓存的views?

final ArrayList mCachedViews= new 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 ListgetScrapList() {

           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;

                }

           }

       }



你可能感兴趣的:(Android)