今天有个需求,有个地区列表要改成可展开收起的列表,正好可以探索一下 recyclerview 的各个组成部分。
今天着重记录一下:ViewHolder、Adapter、AdapterDataObservable、RecyclerViewDataObServer、LayoutManager、Recycler、RecyclerPool。
先上一张图大致描述下他们之间的关系,这张图是 adapter.nofifyXX() 时 Recyclerview 的执行逻辑涉及到的一些类:
ViewHolder
对于Adapter来说,一个ViewHolder就对应一个data。它也是Recycler缓存池的基本单元。
1 | public abstract static class ViewHolder { |
上面列举了 ViewHolder 中最重要的 4 个属性:
itemView:会被当做 child view 来添加到 RecyclerView 中。
mPosition:标记当前 ViewHolder 在 Adapter 中所处的位置。
mItemViewType:当前 ViewHolder 的 Type,在 ViewHolder 保存到 RecyclerPool 时,主要靠这个类型来对 ViewHolder 做复用。
mFlags:标记ViewHolder的状态,比如 FLAG_BOUND(显示在屏幕上)、FLAG_INVALID(无效,想要使用必须rebound)、FLAG_REMOVED(已被移除)等。
Adapter
其工作是把 data 和 view 绑定,即上面说的一个 data 对应一个 ViewHolder。主要负责 ViewHolder 的创建以及数据变化时通知 RecyclerView。
Adaper 会引用一个数据集合,getItemCount() 用来告诉 RecyclerView 展示的总条目。另外,Adapter 不是直接映射 data -> ViewHolder,而是 data position -> data type ->ViewHolder。所以对于 ViewHolder 来说,它知道的只是它的 view type。
AdapterDataObservable
Adapter 是数据源的直接接触者,当数据源发生变化时,它需要通知给 RecyclerView。这里使用的模式是观察者模式,AdapterDataObservable 是数据源变化是的被观察者, RecyclerViewDataObservable 是观察者。开发中使用的 notifyXX() 刷新 ui,就是抵用的 adapterDataObservable 的 notifyChanged() 。
RecyclerViewDataObserver
继承自 AdapterDataObserver,用来监听 Adapter 的数据变化。
LayoutManager
它是RecyclerView的布局管理者,RecyclerView在onLayout时,会利用它来layoutChildren,它决定了RecyclerView中的子View的摆放规则。但不止如此, 它做的工作还有:
- 测量子View
- 对子View进行布局
- 对子View进行回收
- 子View动画的调度
- 负责RecyclerView滚动的实现
- …
Recycler
对于 LayoutManager 来说,它是 ViewHolder 的提供者。对于 RecyclerView 来说,它是 ViewHolder 的管理者,是 RecyclerView 最核心的实现。下面这张图大致描述了它的组成:
scrap list
1 | final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>(); |
View Scrap状态
相信你在许多 RecyclerView 的 crash log 中都看到过这个单词。它是指 View 在 RecyclerView 布局期间进入分离状态的子视图。即它已经被 deatach(标记为 FLAG_TMP_DETACHED 状态)了。这种 View 是可以被立即复用的。
它在复用时,如果数据没有更新,是不需要调用 onBindViewHolder 方法的。如果数据更新了,那么需要重新调用 onBindViewHolder。
mAttachedScrap 和 mChangedScrap 中的 View 复用主要作用在 adapter.notifyXXX 时。这时候就会产生很多scrap 状态的 view。 也可以把它理解为一个 ViewHolder 的缓存。不过在从这里获取 ViewHolder 时完全是根据ViewHolder 的position 而不是 item type。如果在 notifyXX 时 data 已经被移除掉你,那么其中对应的ViewHolder 也会被移除掉。
mCacheViews
可以把它理解为 RecyclerView 的一级缓存。它的默认大小是3, 从中可以根据 item type 或者 position 来获取ViewHolder。可以通过 RecyclerView.setItemViewCacheSize() 来改变它的大小。
RecycledViewPool
它是一个可以被复用的 ViewHolder 缓存池。即可以给多个 RecycledView 来设置统一个 RecycledViewPool。这个对于多 tab feed 流应用可能会有很显著的效果。它内部利用一个 ScrapData 来保存 ViewHolder 集合:
1 | class ScrapData { |
一个 ScrapData 对应一种 type 的 ViewHolder 集合。看一下它的获取 ViewHolder 和保存 ViewHolder 的方法:
1 | //存 |