RecyclerView的基本设计结构

作者 : 开心源码 本文共4365个字,预计阅读时间需要11分钟 发布时间: 2022-05-12 共149人阅读

RecyclerView作为Android开发中最常用的View之一。很多App的feed流都是使用RecyclerView来实现的。加深对于RecyclerView的掌握对于开发效率和开发质量都有很重要的意义。接下来我打算从源码
角度剖析RecyclerView的实现,加深对于RecycledView的理解。RecyclerView的源码实现还是很庞大的。本文就先来看一下RecyclerView的整体设计,理解其核心实现类的作用以及大致实现原理。

下面这张图是我截取的RecyclerView的Structure:

类的组成.png

本文着重看: ViewHolderAdapterAdapterDataObservableRecyclerViewDataObserverLayoutManager、、RecyclerRecyclerPool。 从而了解RecycledView的大致实现原理。

先用一张图大致形容他们之间的关系,这张图是adapter.notifyXX()RecyclerView的执行逻辑涉及到的少量类:

RecyclerView组成类之间的关系.png

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 viewaddRecyclerView中。
  • mPosition : 标记当前的ViewHolderAdapter中所处的位置。
  • mItemViewType : 这个ViewHolderType,在ViewHolder保存到RecyclerPool时,主要靠这个类型来对ViewHolder做复用。
  • mFlags : 标记ViewHolder的状态,比方 FLAG_BOUND(显示在屏幕上)FLAG_INVALID(无效,想要使用必需rebound)FLAG_REMOVED(已被移除)等。

Adapter

它的工作是把dataView绑定,即上面说的一个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();    }  }

即:

  1. 它引用着一个数据源集合dataSource
  2. getItemCount()用来告诉RecyclerView展现的总条目
  3. 它并不是直接映射data -> ViewHolder, 而是 data position -> data type -> viewholder。 所以对于ViewHolder来说,它知道的只是它的view type

AdapterDataObservable

Adapter是数据源的直接接触者,当数据源发生变化时,它需要通知给RecyclerView。这里使用的模式是观察者模式AdapterDataObservable是数据源变化时的被观察者。RecyclerViewDataObserver是观察者。
在开发中我们通常使用adapter.notifyXX()来刷新UI,实际上Adapter会调用AdapterDataObservablenotifyChanged():

    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的布局管理者,RecyclerViewonLayout时,会利用它来layoutChildren,它决定了RecyclerView中的子View的摆放规则。但不止如此, 它做的工作还有:

  1. 测量子View
  2. 对子View进行布局
  3. 对子View进行回收
  4. 子View动画的调度
  5. 负责RecyclerView滚动的实现

Recycler

对于LayoutManager来说,它是ViewHolder的提供者。对于RecyclerView来说,它是ViewHolder的管理者,是RecyclerView最核心的实现。下面这张图大致形容了它的组成:

Recycler的组成.png

scrap list

final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();ArrayList<ViewHolder> mChangedScrap = null;
  • View Scrap状态

相信你在许多RecyclerViewcrash log中都看到过这个单词。它是指ViewRecyclerView布局期间进入分离状态的子视图。即它已经被deatach(并不是调用了onDetatchToWindow方法, 是被标记为FLAG_TMP_DETACHED状态)了。这种View是可以被立即复用的。它在复用时,假如数据没有升级,是不需要调用onBindViewHolder方法的。假如数据升级了,那么需要重新调用onBindViewHolder

mAttachedScrapmChangedScrap中的View复用主要作用在adapter.notifyXXX时。这时候就会产生很多scrap状态的view。 也可以把它了解为一个ViewHolder的缓存。不过在从这里获取ViewHolder时完全是根据ViewHolderposition而不是item type。假如在notifyXX时data已经被移除掉你,那么其中对应的ViewHolder也会被移除掉。

mCacheViews

可以把它了解为RecyclerView的一级缓存。它的默认大小是2。只能减少不能添加。从中可以根据item type来获取ViewHolder

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对应一种typeViewHolder集合。看一下它的获取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最核心的组成部分(本文并没有形容动画的部分)。

下一篇文章会分析RecyclerView的刷新机制

欢迎关注我的Android进阶计划。看更多干货

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » RecyclerView的基本设计结构

发表回复