天天看点

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

总结一下:Adapter就是让你去子类实现一个多样化的Adapter,以满足不同数据,不同item的view的需求。与观察者来往密切,用来在数据集更新后更改view显示。

private final AdapterDataObservablemObservable = new AdapterDataObservable();//观察者模式

private boolean mHasStableIds= false;

//交给子类实现的onCreateViewHolder抽象方法,很熟悉了

//当RecyclerView需要一个新的给定类型的ViewHolder去代表一个item时被调用。

这个新的ViewHolder应该通过一个新的可以代表给定类型的item的View被构建。

你既可以手动创建一个新的View也可以也可用调用inflate方法把它从xml中解析出来。

新的ViewHolder将会被用来显示Adapter的items通过onBindViewHolder(ViewHolder,int,List)方法。因为它将会被重用去显示不同的items在数据集中,这是一个好主意去缓存对于view的子视图的引用去避免不必要的View#findViewById(int)方法的调用。

public abstract VHonCreateViewHolder(ViewGroup parent, int viewType);

//通篇都是抽象方法,把数据,数据的绑定,子视图都交给子类去实现。Adapter其实已经相当于是一个接口了。

//这个方法被RecyclerView调用用来显示明确位置的数据。这个方法应该更新itemView的内容以反映指定位置的item。

注意不像ListView,RecyclerView不会再次调用这个方法如果item的位置改变了在数据集中。除非这个item本身是不可用的或者新的位置不能被定下来。因此,当获取相关的在这个方法中的数据item你应该仅仅使用position参数,并且不应该保留副本。如果你一会需要这个item的位置比如在点击事件中,使用getAdapterPosition()将会有一个被更新后的Adapter的位置。

重写onBindViewHolder(ViewHolder, int, List)方法最好,当Adapter可以处理高效的部分绑定。

public abstract void onBindViewHolder(VHholder, int position);

//比起上一个方法多了一个有效荷载的集合。这个有效荷载的集合是一个合并的列表,来自于notifyItemChanged(int, Object)方法或者notifyItemRangeChanged(int,int, Object)方法。如果这个有效荷载集合不为空,这个ViewHolder现在会被旧的数据绑定,并且Adapter或许可以运行一个高效的部分使用有效荷载的信息来更新。如果有效荷载是空的,Adapter必须完全绑定。Adapter不应该认为有效荷载通过通知方法将会被onBindViewHolder()接受。举个例子,当view没有被连接到屏幕的时候,notifyItemChange()的有效荷载将会被简单地删除。

//所以我们明白了,有效荷载集合是用来以更新的数据集合来更新视图用的。反正就是更新。

public void onBindViewHolder(VH holder, intposition, List<Object> payloads) {

           onBindViewHolder(holder, position);

       }

//这个方法就是onCreateViewHolder()方法的组合者了。因为onCreateViewHolder()你抽象了交给子类实现了不可能不用吧?所以在和这个方法里调用。我更愿意称呼这个操作叫组合。类似于组合模式。

public final VH createViewHolder(ViewGroupparent, int viewType) {

            //写一个跟踪消息来表示给定的一段代码已经开始。即使是多线程也能追踪,常用于性能分析。

           TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);

           final VH holder = onCreateViewHolder(parent, viewType);

           holder.mItemViewType = viewType;

           TraceCompat.endSection();

           return holder;

       }

public final void bindViewHolder(VH holder,int position) {

           holder.mPosition = position;

            //绑定id。这里hasstableids这个方法里的参数需要看看是在哪里赋值的,很重要

           if (hasStableIds()) {

                holder.mItemId =getItemId(position);

           }

           holder.setFlags(ViewHolder.FLAG_BOUND,

                    ViewHolder.FLAG_BOUND |ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID

                            |ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN);

           TraceCompat.beginSection(TRACE_BIND_VIEW_TAG);

           onBindViewHolder(holder, position, holder.getUnmodifiedPayloads());

           holder.clearPayload();

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

           if (layoutParams instanceof RecyclerView.LayoutParams) {

                ((LayoutParams) layoutParams).mInsetsDirty = true;

           }

           TraceCompat.endSection();

       }

public int getItemViewType(int position) {

           return 0;

       }

//指示数据集中的每个项目是否可以用唯一标识符表示类型,所以这就是stableid的意思

public void setHasStableIds(booleanhasStableIds) {

            //观察者就是用来改变的,在你设置稳定id前,这个Observes无疑应该是空的。

           if (hasObservers()) {

                throw newIllegalStateException("Cannot change whether this adapter has " +

                        "stable IDs whilethe adapter has registered observers.");

           }

           mHasStableIds = hasStableIds;

       }

//当此适配器创建的视图已被回收时调用。

当一个布局管理器决定一个view不再需要去被联系到他的父ReyclerView的时候,这个view被回收。这可能是因为它不可见了,或者一个缓存视图的集合仍然被连接到父RecyclerView。如果一个item的view有大的或者高代价的数据绑定到它身上,就像大的位图,这或许会是一个好地方去释放那些资源。

RecyclerView在清除ViewHolder的内部数据之前调用这个方法发送给RecycledViewPool。这样,如果ViewHolder持有有效的信息在回收之前,您可以调用getAdapterPosition()来获取它的适配器位置。

public void onViewRecycled(VH holder) {

       }

//如果是因为transient状态而导致的无法回收,那么这个方法就会被调用。收到这个回调以后,Adapter可以清除那些影响view的transient状态的动画并且返回true以至于这个view可以被回收。请记住那些有问题的视图已经从recyclerview中移除了。从某些方面来讲,这是可接受的去回收一个view尽管它有transient状态。大多数时候,这是一个transient状态将会在onBindViewHolder(ViewHolder,int)被清除的调用的情况当view被重新绑定到一个新的位置上。因此,recyclerView将决定交给Adapter并且使用返回值去决定这个view是不是应该被回收。注意当所有的动画被RecyclerView.ItemAnimator创建时,你不应该接受这个回调因为recyclerView把这个view作为孩子知道他们的动画被完成。这个回调是很有用的当item的views的孩子创建动画,这或许不太轻易去实现使用一个ItemAnimator。你永远不应该通过调用holder.itemView.setHasTransientState(false);来修复这个情况。除非你之前已经调用了holder.itemView.setHasTransientState(true)。每一个View.setHasTransientState(true)调用必须通过一个View.setHasTransientState(false)的调用来匹配。否则,这个view的状态可能会变得不一致。你应该总是倾向于去结束或者退出动画触发这个transient状态而不是手动处理。

public boolean onFailedToRecycleView(VHholder) {

           return false;

       }

//当view被添加到屏幕上的时候调用这个方法。如果你之前已经在onViewDetachedFromWindow(RecyclerView.ViewHolder)onViewDetachedFromWindow释放了资源。那么这些资源应该在这里被存储。

public void onViewAttachedToWindow(VHholder) {

       }

//从window中解除联系不一定是因为item脱离了窗口,Adapter视图的使用者可能会选择在屏幕之外缓存视图是不可见的,适当的attach和detach他们。

public void onViewDetachedFromWindow(VHholder) {

       }

public final boolean hasObservers() {

           return mObservable.hasObservers();

       }

//注册一个新的观察者来监听数据变化。适配器可以发布描述特定变化的各种事件。

不是所有的适配器都可以支持所有的更改类型,有些可能会回到通用的

AdapterDataObserver#onChanged()事件如果更多的明确的数据是不可用的。

还有使用完了要记得注销观察者。

public voidregisterAdapterDataObserver(AdapterDataObserver observer) {

           mObservable.registerObserver(observer);

       }

public voidunregisterAdapterDataObserver(AdapterDataObserver observer) {

           mObservable.unregisterObserver(observer);

       }

//当recyclerView开始观察Adapter的时候,这个方法被调用。注意同一个Adapter或许可能会被多个recyclerView同时观察。

public voidonAttachedToRecyclerView(RecyclerView recyclerView) {

       }

public void onDetachedFromRecyclerView(RecyclerViewrecyclerView) {

       }

//这个作用不用说了。他有两种情况的改变,item数据的改变。item列表中的插入,删除。这个事件没有指定数据集已经改变了什么,强制任何观察者都认为所有现有的items和结构不再有效。LayoutManager将被迫完全重新绑定和重新布局所有可见的视图。所以这个方法不怎么推荐,recyclerView还有另外的方法可以处理item的变化。实在没办法了你再用这个方法。

public final void notifyDataSetChanged() {

           mObservable.notifyChanged();

       }

//通知某个item的数据变了。

public final void notifyItemChanged(intposition) {

           mObservable.notifyItemRangeChanged(position, 1);

       }

//多了一个payload讲了一大串我不是很懂的东西。意思是null的payload等同于全部item都更新。但是简单追溯了下源码,发现payload根本没有用上。不过也不是太重要。

public final void notifyItemChanged(intposition, Object payload) {

           mObservable.notifyItemRangeChanged(position, 1, payload);

       }

//通知任何注册的观察者:itemCount项目的起始位置位置positionStart已经改变。等同于调用notifyItemRangeChanged(position,itemCount,null); 这是项目更改事件,而不是结构更改事件。 这表明数据在给定位置范围内的任何反映都是过时的,应该这样做被更新。给定范围内的项目保留相同的身份

public final voidnotifyItemRangeChanged(int positionStart, int itemCount) {

           mObservable.notifyItemRangeChanged(positionStart, itemCount);

       }

//可选的有效载荷可以是传递给每个更改的项目。

public final voidnotifyItemRangeChanged(int positionStart, int itemCount, Object payload) {

           mObservable.notifyItemRangeChanged(positionStart, itemCount, payload);

       }

public final void notifyItemInserted(intposition) {

           mObservable.notifyItemRangeInserted(position, 1);

       }

public final void notifyItemMoved(intfromPosition, int toPosition) {

           mObservable.notifyItemMoved(fromPosition, toPosition);

       }

//与notifyItemInserted(intposition)区别就是这次插入的是几项不是一项

public final voidnotifyItemRangeInserted(int positionStart, int itemCount) {

           mObservable.notifyItemRangeInserted(positionStart, itemCount);

       }

public final void notifyItemRemoved(intposition) {

           mObservable.notifyItemRangeRemoved(position, 1);

       }

public final voidnotifyItemRangeRemoved(int positionStart, int itemCount) {

           mObservable.notifyItemRangeRemoved(positionStart, itemCount);

       }