下面这张图是我截取的RecyclerView的Structure:
本文着重看: ViewHolder
、Adapter
、AdapterDataObservable
、RecyclerViewDataObserver
、LayoutManager
、、Recycler
、RecyclerPool
。 从而理解RecycledView
的大致实现原理。
先用一张图大致描述他们之间的关系,这张图是adapter.notifyXX()
时RecyclerView
的执行逻辑涉及到的一些类:
ViewHolder
对于Adapter
来说,一个ViewHolder
就对应一个data
。它也是Recycler缓存池
的基本单元。
class ViewHolder {
public final View itemView;
int mPosition = NO_POSITION;
int mItemViewType = INVALID_TYPE;
int mFlags;
...
}
上面我列出了ViewHolder
最重要的4个属性:
- itemView : 会被当做
child view
来add
到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
的创建以及数据变化时通知RecycledView
。比如下面这个Adapter:
class SimpleStringAdapter(val dataSource: List<String>, val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder.itemView is ViewHolderRenderProtocol) {
(holder.itemView as ViewHolderRenderProtocol).render(dataSource[position], position)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = SimpleVH(SimpleStringView(context))
override fun getItemCount() = dataSource.size
override fun getItemViewType(position: Int) = 1
override fun notifyDataSetChanged() { //super的实现
mObservable.notifyChanged();
}
}
即:
- 它引用着一个数据源集合
dataSource
getItemCount()
用来告诉RecyclerView
展示的总条目- 它并不是直接映射
data -> ViewHolder
, 而是data position -> data type -> viewholder
。 所以对于ViewHolder
来说,它知道的只是它的view type
AdapterDataObservable
Adapter
是数据源的直接接触者,当数据源发生变化时,它需要通知给RecyclerView
。这里使用的模式是观察者模式
。AdapterDataObservable
是数据源变化时的被观察者。RecyclerViewDataObserver
是观察者。
在开发中我们通常使用adapter.notifyXX()
来刷新UI,实际上Adapter
会调用AdapterDataObservable
的notifyChanged()
:
public void notifyChanged() {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
逻辑很简单,即通知Observer
数据发生变化。
RecyclerViewDataObserver
它是RecycledView
用来监听Adapter
数据变化的观察者:
public void onChanged() {
mState.mStructureChanged = true; // RecycledView每一次UI的更新都会有一个State
processDataSetCompletelyChanged(true);
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
LayoutManager
它是RecyclerView
的布局管理者,RecyclerView
在onLayout
时,会利用它来layoutChildren
,它决定了RecyclerView
中的子View的摆放规则。但不止如此, 它做的工作还有:
- 测量子View
- 对子View进行布局
- 对子View进行回收
- 子View动画的调度
- 负责
RecyclerView
滚动的实现 - …
Recycler
对于LayoutManager
来说,它是ViewHolder
的提供者。对于RecyclerView
来说,它是ViewHolder
的管理者,是RecyclerView
最核心的实现。下面这张图大致描述了它的组成:
scrap list
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
ArrayList<ViewHolder> mChangedScrap = null;
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
。可以通过RecycledView.setItemViewCacheSize()
来改变它的大小。
RecycledViewPool
它是一个可以被复用的ViewHolder
缓存池。即可以给多个RecycledView
来设置统一个RecycledViewPool
。这个对于多tab feed流
应用可能会有很显著的效果。它内部利用一个ScrapData
来保存ViewHolder
集合:
class ScrapData {
final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
int mMaxScrap = DEFAULT_MAX_SCRAP; //最多缓存5个
long mCreateRunningAverageNs = 0;
long mBindRunningAverageNs = 0;
}
SparseArray<ScrapData> mScrap = new SparseArray<>(); //RecycledViewPool 用来保存ViewHolder的容器
一个ScrapData
对应一种type
的ViewHolder
集合。看一下它的获取ViewHolder
和保存ViewHolder
的方法:
//存
public void putRecycledView(ViewHolder scrap) {
final int viewType = scrap.getItemViewType();
final ArrayList<ViewHolder> scrapHeap = getScrapDataForType(viewType).mScrapHeap;
if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) return; //到最大极限就不能放了
scrap.resetInternal(); //放到里面,这个view就相当于和原来的信息完全隔离了,只记得他的type,清除其相关状态
scrapHeap.add(scrap);
}
//取
private ScrapData getScrapDataForType(int viewType) {
ScrapData scrapData = mScrap.get(viewType);
if (scrapData == null) {
scrapData = new ScrapData();
mScrap.put(viewType, scrapData);
}
return scrapData;
}
以上所述,是RecycledView
最核心的组成部分(本文并没有描述动画的部分)。接下来会继续分析RecycledView
是如何利用它们来工作起来的。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/20186,转载请注明出处。
评论0