Android——RecyclerView——ViewHolder全部源码及翻译、注释

来源:互联网 发布:淘宝特种经营许可申请 编辑:程序博客网 时间:2024/06/07 11:13

看了rv的源码 知道了他有 viewholder、动画类、自己定义的layoutparams类,recycler类等。


viewHolder:相当于就是一个item,只不过建了这样一个类,去维护这个item,以及view的全部元数据。


//内部维护1个item,在oncreateviewholder中,每次都是不一样的itemview

public final View itemView;

WeakReference<RecyclerView>mNestedRecyclerView;//维护一个嵌套rv的弱引用?

int mPosition = NO_POSITION;//当前位置

int mOldPosition = NO_POSITION;//老的位置

long mItemId = NO_ID;//item id指的是他的资源id

int mItemViewType = INVALID_TYPE;// ItemViewType是什么?

int mPreLayoutPosition = NO_POSITION;//上一个LayoutPosition

 

//已经隐藏的item的holder,在一个item改变的事件和动画?

ViewHolder mShadowedHolder = null;

//正在隐藏的item的holder,在一个item改变的事件和动画?

ViewHolder mShadowingHolder = null;

 

//左移运算符:左移0位,不翻倍,还是1

 

//标识:是ViewHolder已经绑定一个position(元数据:mPosition, mItemId andmItemViewType)

static final int FLAG_BOUND = 1 << 0;

 

//标识:更新

//这个ViewHolder的视图反映的数据是陈旧的,需要由adapter为他重新绑定view。mPosition和mItemId是一致的。

static final int FLAG_UPDATE = 1 <<1;

 

//标识:不可用

//这个ViewHolder的数据是无效的。 mPosition和mItemId所暗示的身份

不被信任,可能不再与项目视图类型相匹配。这个ViewHolder必须完全被重新绑定到不同的数据。

static final int FLAG_INVALID = 1 <<2;

 

//标识:已被移除

//这个ViewHolder指向的数据表示从之前的项目数据集中删除的item。 它的视图仍然可以用于出场(outgoing)动画等。

static final int FLAG_REMOVED = 1 <<3;

 

//标识:不可被回收(重复利用)

//这个ViewHolder不应该被回收。这个标志是通过setIsRecyclable()方法被设置的,

并且这个标志是被打算用来维持views大约在动画期间。(所以应该是在动画期间的时候,这个item是被设置成这个状态,为了防止出错)

static final int FLAG_NOT_RECYCLABLE = 1<< 4;

 

//标识:从废品中被返回

//这个ViewHolder是从废品中返回的,这意味着我们期待着一个addView()方法的调用

把这个itemView重新加入回去。当从废品中返回的时候,如果ViewHolder没有被添加回RecyclerView(意思就是没有从废品堆里出来),ViewHolder会待在废品列表里直到这个布局的底部pass(意思就是那个被隐藏的item显示出来了),再通过recyclerView被回收出来

static final int FLAG_RETURNED_FROM_SCRAP =1 << 5;

 

//标识:使某个ViewHolder被置为不可操作状态

//这个ViewHolder是完全被LayoutManager管理的,(意思就是所有的item在recyclerView中的排列方式是由LayoutManager管理的。比如是LinearLayoutManager,那RecyclerView就好像一个LinerLayout,如果是GridManager(我也记不清叫啥了),那就像是网格状的)

(接下来是忽略的意思)我们不会使这个viewholder报废,被回收,被移除,除非这个LayoutManager被替换掉了(不太明白被替换是什么意思,应该理解为是这个item被移出可见区域的这个操作)。此外,这个ViewHolder仍然完全可见对于这个LayoutManager。

static final int FLAG_IGNORE = 1 <<7;

 

//标识:被移除

//当这个view被从父viewgroup中分离出来时,我们设置这个标志。我们设置这个标志是为了我们可以采取正确的行动当我们需要移除这个viewholder或者把他添加回去。

static final int FLAG_TMP_DETACHED = 1<< 8;

 

//标识:Adapter位置未知

//当我们不能确定这个ViewHolder的适配器的位置时,我们设置这个标识。直到这个ViewHolder被重新绑定到新的位置,我们取消这个标志。这个标识不同于FLAG_INVALID,因为FLAG_INVALID即使在类型不匹配(?)的时候也可以被设置。此外,我们这个标志是当Adapter的通知到达时立即被设置的。而FLAG_INVALID是在布局被重新计算之前被懒惰地设置。

static final intFLAG_ADAPTER_POSITION_UNKNOWN = 1 << 9;

 

//标识:Adapter被(?)完全更新了

//当addChangePayload(null)这个方法被调用的时候,我们设置这个标识。

static final int FLAG_ADAPTER_FULLUPDATE =1 << 10;

 

//标识:已被移除

static final int FLAG_MOVED = 1 <<11;

 

//标识:显示在之前的布局(?)

//ViewHolder出现在预布局(之前的布局?)中时,由ItemAnimator使用

static final int FLAG_APPEARED_IN_PRE_LAYOUT= 1 << 12;

 

//标识:等待的可达到的状态未设置(?)

static final intPENDING_ACCESSIBILITY_STATE_NOT_SET = -1;

 

//标识:从隐藏的列表中被弹回

//当ViewHolder作为隐藏的ViewHolder启动布局传递时使用,但是被重用

隐藏的列表(就好像是废品),而不被回收。

当一个ViewHolder被隐藏时,有两个路径可以被重用:

   a)动画结束,视图从回收池回收和使用。

   b)当ViewHolder被隐藏时,LayoutManager要求查看该位置

这个标志被用来表示ViewHolder被重用的情况b

回收(因此从隐藏清单中“反弹”)。 这个状态需要特殊处理

因为必须将ViewHolder添加到动画的预布局贴图中,就好像它一样

已经在那了。

static final intFLAG_BOUNCED_FROM_HIDDEN_LIST = 1 << 13;

 

private int mFlags;

//标识:完全更新的有效荷载

// Collections.EMPTY_LIST:一个空的,常量,已经被序列化后的集合

private static final List<Object>FULLUPDATE_PAYLOADS = Collections.EMPTY_LIST;

 

//有效荷载

List<Object> mPayloads = null;

//未更改的有效荷载

List<Object> mUnmodifiedPayloads =null;

 

//可回收数量

private int mIsRecyclableCount = 0;

 

//如果这个废品容纳者不为空(Recycler类是废品容纳者),view目前将会被认为是废品,并且或许被另外的数据重用通过废品容纳者。

private Recycler mScrapContainer = null;

 

//标识:在改变的废品(?)

//为true的时候:1.ViewHolder存在于改变的废品2.ViewHolder存在于被添加的废品中

private boolean mInChangeScrap = false;

 

//标识:是不是对于在被隐藏之前可进入的很重要,(ViewCompat是提供兼容性的类),后面的参数是自动决定一个view对于可进入性是重要的

//当这个view处在被隐藏的状态中,并且被标记为对于可进入性不重要时,保存“isImportantForAccessibility”的值给view。

private intmWasImportantForAccessibilityBeforeHidden =

               ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;

 

//@VisibleForTesting代表让类,方法,或区域(?值域,堆栈空间)的可见性更放松,以至于可视区域更宽,让代码可测试

//如果我们推迟了这个viewholder的可见状态,我们需要设置这个属性

@VisibleForTesting

int mPendingAccessibilityState =PENDING_ACCESSIBILITY_STATE_NOT_SET;

//这个ViewHolder的宿主rv

//当ViewHolder被绑定(弹回?)从Adapter并且在被送去rv池清扫之前设置这个rv。

RecyclerView mOwnerRecyclerView;

 

public ViewHolder(View itemView) {

if (itemView == null) {

throw newIllegalArgumentException("itemView may not be null");

}

this.itemView = itemView;

}

 

//把flag变成移除,(设置?)偏移位置

void flagRemovedAndOffsetPosition(intmNewPosition, int offset, boolean applyToPreLayout) {

    //把ViewHolder.FLAG_REMOVED和旧的flag进行二进制加法(按位或),成为新的flag存入当前维护的flag

addFlags(ViewHolder.FLAG_REMOVED);

//设置偏移位置,设置是否应用到之前的布局

   offsetPosition(offset, applyToPreLayout);

   mPosition = mNewPosition;

}

 

void offsetPosition(int offset, booleanapplyToPreLayout) {

           if (mOldPosition == NO_POSITION) {

                mOldPosition = mPosition;

           }

           if (mPreLayoutPosition == NO_POSITION) {

                mPreLayoutPosition =mPosition;// PreLayoutPosition?

           }

           if (applyToPreLayout) {

                mPreLayoutPosition += offset;

           }

           mPosition += offset;

           if (itemView.getLayoutParams() != null) {

//这里把布局参数转成自己定义的布局参数类

                ((LayoutParams)itemView.getLayoutParams()).mInsetsDirty = true;

           }

}

 

void clearOldPosition() {

           mOldPosition = NO_POSITION;

           mPreLayoutPosition = NO_POSITION;

}

 

void saveOldPosition() {

           if (mOldPosition == NO_POSITION) {//为什么这个状态的时候才能保存旧状态

                mOldPosition = mPosition;

           }

}

 

//应该忽略?

boolean shouldIgnore() {

           return (mFlags & FLAG_IGNORE) != 0;

}

 

//被注释@Deprecated的程序元素是程序员不鼓励使用,通常是因为它是危险的,

或者因为有更好的选择。

//这个方法被弃用了,因为因为这个方法的含义是异步的,为什么这个方法的含义是异步的呢?因为Adapter的异步处理更新了。现在鼓励使用getLayoutPosition(),getAdapterPosition()

@Deprecated

public final int getPosition() {

           return mPreLayoutPosition == NO_POSITION ? mPosition : mPreLayoutPosition;

}

 

//根据最新的布局传递返回ViewHolder的位置。这个位置主要是由RecyclerView组件来保持一致的,RecyclerView懒洋洋地处理适配器更新。出于性能和动画的原因,RecyclerView将批处理所有适配器更新直到下一个布局传递过来(?)。这可能会导致Adapter中item的位置和最近一次中已经计算好的位置不匹配。LayoutManagers当做有关item位置的计算时应该调用这个方法。所有在RecyclerView.LayoutManager,RecyclerView.State,RecyclerView.Recycler3个类中接收一个位置的方法,都期待这个(?)变成这个item的布局位置。如果LayoutManager需要调用一个要求这个item位置的Adapter的外部方法,他可以使用getAdapterPosition()或者RecyclerView.Recycler#convertPreLayoutPositionToPostLayout(int)。

public final int getLayoutPosition() {

           return mPreLayoutPosition == NO_POSITION ? mPosition :mPreLayoutPosition;

}

 

//返回这个Adapter中由ViewHolder来代表的的item的位置,注意这个或许是与getLayoutPosition()返回的结果是不同的,如果有等待中的Adapter更新但是一个新的布局传递事件(?)还没有发生。RecyclerView不处理任何Adapter的更新知道下一个布局遍历。这个或许创造临时的在用户看到的和Adapter中的内容不一致。这个不一致并不重要因为它小于16ms但是这或许是一个问题如果你想要去使用ViewHolder的位置去访问Adapter。有时候,你或许需要去取得确切的Adapter的位置去做一些响应用户事件的操作。在这种情况下,你应该使用这个可以计算这个ViewHolder在Adapter中位置的方法。注意,如果你已经调用了RecyclerView.Adapter#notifyDataSetChanged(),直到下一个布局传递过来,这个方法的返回值将会是NO_POSITION。

//notifyDataSetChanged()的使用时机,1.上一个布局传递(事件)2.ViewHolder已经被回收

public final int getAdapterPosition() {

           if (mOwnerRecyclerView == null) {

                return NO_POSITION;

           }

           return mOwnerRecyclerView.getAdapterPositionFor(this);

}

 

//当LayoutManager支持动画的时候,recyclerView追踪3个位置为ViewHolder去执行动画。如果一个ViewHolder被放置在先前的onLayout (?)调用中,老的位置将会保持它的Adapter的索引位置在先前的布局中。

public final int getOldPosition() {

           return mOldPosition;

}

 

//这里的itemid是一个由ViewHolder代表的itemId。

public final long getItemId() {

           return mItemId;

}

 

//返回这个viewholder中view的类型

public final int getItemViewType() {

           return mItemViewType;

}

 

boolean isScrap() {

//如果viewholder中维护的recycler不为空,那就是这个viewholder报废了,所以这个报废与否看recycler就行了

           return mScrapContainer != null;

}

 

//这里是调用recycler的unscrapView方法,让这个viewholder变得不可被回收,直到这个viewholder被报废或者它明确地被移除或者回收了。(我猜测这个item处于布局边界的时候就应该变成不可回收状态了)

void unScrap() {

           mScrapContainer.unscrapView(this);

}

 

//判断这个ViewHolder是否从废品堆中返回的(?是这样吗)

boolean wasReturnedFromScrap() {

           return (mFlags & FLAG_RETURNED_FROM_SCRAP) != 0;

       }

 

//清除“FLAG_RETURNED_FROM_SCRAP”这个falg

void clearReturnedFromScrapFlag() {

           mFlags = mFlags & ~FLAG_RETURNED_FROM_SCRAP;

       }

 

//清除 “FLAG_TMP_DETACHED”这个flag

void clearTmpDetachFlag() {

           mFlags = mFlags & ~FLAG_TMP_DETACHED;

       }

 

void stopIgnoring() {

           mFlags = mFlags & ~FLAG_IGNORE;

       }

 

void setScrapContainer(Recycler recycler,boolean isChangeScrap) {

           mScrapContainer = recycler;

           mInChangeScrap = isChangeScrap;

       }

 

//我猜测不可被复用的情况是暂时的,不知道某个item,error的时候会不会也这样

boolean isInvalid() {

           return (mFlags & FLAG_INVALID) != 0;

       }

 

boolean needsUpdate() {

           return (mFlags &FLAG_UPDATE) != 0;

       }

 

boolean isBound() {

           return (mFlags & FLAG_BOUND) != 0;

       }

 

boolean isRemoved() {

           return (mFlags & FLAG_REMOVED) != 0;

       }

 

//判断是否有任何flag加持着

boolean hasAnyOfTheFlags(int flags) {

           return (mFlags & flags) != 0;

       }

 

//tmp莫非是temp?不太明白

boolean isTmpDetached() {

           return (mFlags & FLAG_TMP_DETACHED) != 0;

       }

 

boolean isAdapterPositionUnknown() {

           return (mFlags & FLAG_ADAPTER_POSITION_UNKNOWN) != 0 || isInvalid();

       }

 

void setFlags(int flags, int mask) {

           mFlags = (mFlags & ~mask) | (flags & mask);

       }

 

//我只能说这里的flag高大上,相比正常的性能会更好吗?

void addFlags(int flags) {

            mFlags |= flags;

       }

 

//增加改变的有效荷载,还是不太明白

void addChangePayload(Object payload) {

           if (payload == null) {

               addFlags(FLAG_ADAPTER_FULLUPDATE);

           } else if ((mFlags & FLAG_ADAPTER_FULLUPDATE) == 0) {

                createPayloadsIfNeeded();

                mPayloads.add(payload);

           }

       }

 

private void createPayloadsIfNeeded() {

           if (mPayloads == null) {

                mPayloads = newArrayList<Object>();

                mUnmodifiedPayloads =Collections.unmodifiableList(mPayloads);

           }

       }

 

void clearPayload() {

           if (mPayloads != null) {

                mPayloads.clear();

           }

           mFlags = mFlags & ~FLAG_ADAPTER_FULLUPDATE;

       }

 

List<Object> getUnmodifiedPayloads(){

           if ((mFlags & FLAG_ADAPTER_FULLUPDATE) == 0) {

                if (mPayloads == null ||mPayloads.size() == 0) {

                    // Initial state,  no update being called.

                    return FULLUPDATE_PAYLOADS;

                }

                // there are none-null payloads

                return mUnmodifiedPayloads;

           } else {

                // a full update has beencalled.

                return FULLUPDATE_PAYLOADS;

           }

       }

 

//重置内部所有属性

void resetInternal() {

           mFlags = 0;

           mPosition = NO_POSITION;

           mOldPosition = NO_POSITION;

           mItemId = NO_ID;

           mPreLayoutPosition = NO_POSITION;

            mIsRecyclableCount = 0;

           mShadowedHolder = null;

           mShadowingHolder = null;

           clearPayload();

           mWasImportantForAccessibilityBeforeHidden =ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;

           mPendingAccessibilityState = PENDING_ACCESSIBILITY_STATE_NOT_SET;

           clearNestedRecyclerViewIfNotNested(this);

       }

 

//当view的item不可见的时候,使view不可访问(为了啥?安全、稳定性的考虑吗)

private voidonEnteredHiddenState(RecyclerView parent) {

           // While the view item is in hidden state, make it invisible for theaccessibility.

           mWasImportantForAccessibilityBeforeHidden =

                   ViewCompat.getImportantForAccessibility(itemView);

           parent.setChildImportantForAccessibilityInternal(this,

                   ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);

       }

 

private void onLeftHiddenState(RecyclerViewparent) {

           parent.setChildImportantForAccessibilityInternal(this,

                   mWasImportantForAccessibilityBeforeHidden);

           mWasImportantForAccessibilityBeforeHidden =ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO;

       }

 

//设置是否可回收,设置是否可回收一定要是一一对应的(不能设置了不可回收之后再设置不可回收这种情况)。此外成对的调用是嵌套的,因为状态是内部引用计数的。这个方法印证了我们的猜测,是有时置为可回收,有时置位不可回收,如边缘状态(?)。

public final void setIsRecyclable(booleanrecyclable) {

           mIsRecyclableCount = recyclable ? mIsRecyclableCount - 1 :mIsRecyclableCount + 1;

           if (mIsRecyclableCount < 0) {

                mIsRecyclableCount = 0;

                if (DEBUG) {

                    throw newRuntimeException("isRecyclable decremented below 0: " +

                            "unmatchedpair of setIsRecyable() calls for " + this);

                }

                Log.e(VIEW_LOG_TAG,"isRecyclable decremented below 0: " +

                        "unmatched pair ofsetIsRecyable() calls for " + this);

           } else if (!recyclable && mIsRecyclableCount == 1) {

                mFlags |= FLAG_NOT_RECYCLABLE;

           } else if (recyclable && mIsRecyclableCount == 0) {

                mFlags &=~FLAG_NOT_RECYCLABLE;

           }

           if (DEBUG) {

                Log.d(TAG,"setIsRecyclable val:" + recyclable + ":" + this);

           }

       }

 

//是否我们有动画正在引用这个viewholder。跟是否可回收这个flag相似的,但是不检查transient(transient通常用来不让标识某个属性不被序列化)状态。

private boolean shouldBeKeptAsChild() {

           return (mFlags & FLAG_NOT_RECYCLABLE) != 0;

       }

 

//判断是否viewHolder被recyclerView的动画引用但是有transient属性状态来避免vh被回收

private booleandoesTransientStatePreventRecycling() {

           return (mFlags & FLAG_NOT_RECYCLABLE) == 0 &&ViewCompat.hasTransientState(itemView);

       }

 

boolean isUpdated() {

           return (mFlags & FLAG_UPDATE) != 0;

       }


阅读全文
0 0
原创粉丝点击