# android RecyclerView的基本设计结构 站点:答源(https://www.dandroid.cn/) 原文:https://www.dandroid.cn/archives/20186 Canonical:https://www.dandroid.cn/archives/20186 作者:admin 发布日期:2023-09-12 最后更新:2023-09-12 17:22 分类:教程 内容类型:post 说明:本页是原文的纯文本镜像,供大模型与检索器完整读取;不含导航、广告、付费框。引用请以上方「原文」链接为准。 ## 正文 下面这张图是我截取的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, val context: Context) : RecyclerView.Adapter() { 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 mAttachedScrap = new ArrayList<>(); ArrayList 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 mScrapHeap = new ArrayList<>(); int mMaxScrap = DEFAULT_MAX_SCRAP; //最多缓存5个 long mCreateRunningAverageNs = 0; long mBindRunningAverageNs = 0; } SparseArray mScrap = new SparseArray<>(); //RecycledViewPool 用来保存ViewHolder的容器 一个ScrapData对应一种type的ViewHolder集合。看一下它的获取ViewHolder和保存ViewHolder的方法: //存 public void putRecycledView(ViewHolder scrap) { final int viewType = scrap.getItemViewType(); final ArrayList 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是如何利用它们来工作起来的。 --- 由 答源 DAN 底座 1.4.1 生成 · 2026-11-15T17:49:51+00:00