RecyclerView这个控件出来已经有一段时间了,如果看这篇文章的你,还没有使用过这个控件。那请先去学习怎样使用。不然看也白看。这里奉上一些关于介绍RecyclerView使用方法的优秀博客:

这几篇文章都是介绍RecyclerView使用方法的精品文章,其次还有很多大神做的RecyclerView的第三方库,这里我就不一一列举了,自己去按需搜索吧。

然后对于已经对RecyclerView有初步了解的读者,我们一起步入本文的正题。

RecyclerView的设计目的

研究一个现有的控件,先看看这个控件的设计目的是什么。其实就是看看RecyclerView是干什么的。官方对RecyclerView的介绍是很简短的一句话:

A flexible view for providing a limited window into a large data set.

一个用来为大量数据集合提供有限窗口的灵活的视图。我的翻译有点怪,自己看英文理解。介绍言简意赅,一针见血...好,我没词儿了。

其中关键的有两点:

  • providing a limited window into a large data set
  • flexible

针对与这两点我们可以看看RecyclerView的整体设计。

RecyclerView整体设计

RecyclerView中,针对要达到的功能点,都有相关的设计,下面分点来分析RecyclerView的设计。

RecyclerView数据展示的设计思路

在上一节中提到的,其设计目的的第一点就是展示大量数据。其实RecyclerView在这一点上和ListView等控件具有相同的设计思路,都是使用了设计模式中的适配器模式。不过即使你不知道适配器模式也不用担心。

首先呢,来看一张 巨丑无比 但是 简单明了 的结构图:

图一

首先RecyclerView是一个ViewGroup,它和我们常用的各种Layout一样,是用来装很多子View的容器,那么它里面装的那些View是怎么来的呢?其实是来自ViewHolder中的itemView的。那么ViewHolder是从哪里生成的呢?显示的数据又是在哪里设置的呢?这就是Adapter的作用,它根据要展示数据的内容和类型,生成相应的ViewHolder,并对相应的View进行设置,从而展示出来。

如果从数据源出发就是,Adapter将要展示的数据根据其内容和类型,转化成对应的ViewHolder并对其进行设置,然后RecyclerView把ViewHolder中的itemView展示出来。

如果把这个图套用到适配器模式中,RecyclerView就是其中的Client,ViewHolder就是Target,Adapter自然就是Adapter,Data就是Adaptee。我这个图没有严格去按照适配器模式中的画是为了让即使不知道适配器模式的人也能看懂。

这个结构其实不通过源码也可以看出,在使用RecyclerView的时候也可以体会到。其中由Data生成对应用于展示的ViewHolder,就是通过实现Adapter中的onCreateViewHolder(ViewGroup parent, int viewType);onBindViewHolder(VH holder, int position);这两个方法。

设计目的中的第一点我们清楚了,那么我们来看第二点。

RecyclerView flexible的设计思路

在研究和探讨这个问题的之前我们需要具体化flexible。那么RecyclerView有哪些地方体现出了flexible?个人拙见有以下几点:

  1. 布局
  2. 动画
  3. 装饰

这些大家基本也都知道。那么我们分别看它在每个功能点上面的设计:

RecyclerView布局策略设计思路

细心的读者应该在上图中发现,在ViewHolder到RecyclerView的箭头上有三个点,其实就是暗示了这其中还有很多的猫腻!

还是先上一张 巨丑无比 但 简单明了 的图。

图二

RecyclerView布局十分灵活,是因为RecyclerView将自己的布局策略全权交给了LayoutManager。仔细阅读源码还可以发现,就连View的添加,都是通过LayoutManager完成的。LayoutManager所做的事情就是拿到ViewHolder中的itemView,然后根据LayoutManager中定义的布局策略,对itemView进行布局,然后添加到RecyclerView中。

因此使用者可以根据自己的需要,自定义布局策略,而这里系统提供好了三种布局策略,线性布局,网格布局和瀑布流布局。一般情况下这三种已经满足了我们的需求。如果不能,用户可以自定义布局策略。

RecyclerView动画过程系统设计思路

RecyclerView作为一种展示大量数据的视图控件,难免会遇到数据变化的情况。例如添加,删除,更改等。当这些事情发生的时候,猿人往往喜欢通过动画来体现这种变化。那么在RecyclerView中便提供了一种非常灵活的动画机制。

同样先上一张 巨丑无比 但 简单明了 的图。

图三

首先,达到数据改变触发动画,我们通常使用Adapter中的notifyXXX方法即可。但是其内部是如何工作的呢?

其实notify系列的方法可以看作是发出一个事件,在这里Adapter和RecyclerView的工作原理,是一个典型的观察者模式。

RecyclerView是观察者,Adapter是可观察的,在设置Adapter的时候RecyclerView订阅观察事件,当Adapter中的数据发生改变的时候通知RecyclerView。然后RecyclerView接到通知之后进行了很多处理。并触发重新布局。在布局过程中又经过一系列处理,将这些动画的信息存储到ViewInfoStore中。在布局结束的时候由ViewInfoStore统一处理并通过CallBack中的方法调用ItemAnimator中的方法执行动画。

RecyclerView动画的灵活性是通过ItemAnimator实现的。各位猿们可以通过继承ItemAnimator,然后实现里面的方法,来实现各种各样的动画效果。

RecyclerView装饰系统设计思路

这里其实并没有什么好讲的,实现ItemDecoration类中的抽象函数即可。RecyclerView内部就是在onDraw的时候执行ItemDecoration的onDraw,在draw的时候执行ItemDecoration的onDrawOver函数。在计算itemView的padding的时候将getItemOffsets得到的Rect加入其中,从而空出装饰内容的区域。其灵活性在于程序员们可以自定义ItemDecoration,实现各种各样的装饰。

对于ItemDecoration有一篇文章介绍的比较好,在这里推荐给大家。

建林大神的 深入理解 RecyclerView 系列之一:ItemDecoration其中也进行了深入讲解,而且我觉的可以了,这部分源码也没多少,很简单。

RecyclerView视图复用的设计思路

结合前两节的内容,我们的结构图应该成这个样子了(动画部分于该节无关,省略动画部分结构图):

图四

其中ViewHolder的那一列很奇怪,是有多少个Data就有多少ViewHolder吗?ViewHolder是存储在哪里的?

那么将RecyclerView的复用结构补充上。又一张 巨丑无比 但 简单明了 的图。

图五

这个相对于图四多了一个Recycler和RecyclerViewPool。这两个可能都不熟悉,那么对这两个类进行一个简单的介绍:

Recycler

A Recycler is responsible for managing scrapped or detached item views for reuse.

一个Recycler是负责管理成为碎片的视图或者已经detached的视图,从而实现View的复用。

RecyclerViewPool

RecycledViewPool lets you share Views between multiple RecyclerViews.

RecycledViewPool可以让你在多个RecyclerView之间分享视图

翻译的不好,不能忍的看原文。

介绍都说的很明白了,还有其实ViewHolder的创建和bind都是由Recycler执行的。还有LayoutManager获得ViewHolder的itemView,也是通过Recycler提供的。简单介绍一下Recycler和RecyclerViewPool的内部结构。

  1. Recycler里有几个ViewHolder的容器,用来存储不同状态的ViewHolder,以便之后复用。其中ViewCacheExtension类,是用户可以自定义复用机制的类。
  2. RecyclerViewPool,这个可以从外部对多个RecyclerView设置同一个RecyclerViewPool,从而实现多个RecyclerView中的ViewHolder的复用。

总结

本章简单的介绍了RecyclerView内部设计的大体框架结构。接下来会详细的介绍主要流程和机制。整理源码很费体力,如果这篇文章让你有所收获,请不要吝惜你的喜欢,你的喜欢是我写作的动力。

作者:柴泽建_Jack
链接:https://www.jianshu.com/p/9ddfdffee5d3
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

RecyclerView源码分析(一)--整体设计的更多相关文章

  1. RecyclerView 源码分析(二) —— 缓存机制

    在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ...

  2. ibatis源码学习1_整体设计和核心流程

    背景介绍ibatis实现之前,先来看一段jdbc代码: Class.forName("com.mysql.jdbc.Driver"); String url = "jdb ...

  3. [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构

    [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构 目录 [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构 0x00 摘要 0x01 文件简介 0x02 总体架构 0x03 总体代码 0x0 ...

  4. RecyclerView 源码分析(一) —— 绘制流程解析

    概述 对于 RecyclerView 是那么熟悉又那么陌生.熟悉是因为作为一名 Android 开发者,RecyclerView 是经常会在项目里面用到的,陌生是因为只是知道怎么用,但是却不知道 Re ...

  5. Duilib源码分析(六)整体流程

    在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...

  6. Duilib源码分析(一)整体框架

    Duilib界面库是一款由杭州月牙儿网络技术有限公司开发的界面开源库,以viksoe项目下的UiLib库的基础上开发(此后也将对UiLib库进行源码分析):通过XML布局界面,将用户界面和处理逻辑彻底 ...

  7. 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计

    问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...

  8. jQuery 2.0.3 源码分析core - 整体架构

    拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery ...

  9. Sizzle源码分析:一 设计思路

    一.前言 DOM选择器(Sizzle)是jQuery框架中非常重要的一部分,在H5还没有流行起来的时候,jQuery为我们提供了一个简洁,方便,高效的DOM操作模式,成为那个时代的经典.虽然现在Vue ...

随机推荐

  1. php中直接执行mysqli_init()也是报Property access is not allowed yet的错误。

    xdebug.auto_trace = On 和 xdebug.profiler_enable = On注释掉就OK了,不知道这两个配置项是干嘛的

  2. 【PAT】1018 锤子剪刀布 (20)(20 分)

    1018 锤子剪刀布 (20)(20 分) 大家应该都会玩“锤子剪刀布”的游戏:两人同时给出手势,胜负规则如图所示: 现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算 ...

  3. JSTL使用

    1.标签函数库 核心标签库                 c I18N格式标签库   fmt SQL标签库  sql XML标签库  xml 函数标签库 fn 2.JSTL支持EL 二:表达式标签 ...

  4. Ionic入门二:网格(Grid)页面布局

    ionic 的网格(Grid)和其他大部分框架有所不同,它采用了弹性盒子模型(Flexible Box Model) .而且在移动端,基本上的手机都支持.row 样式指定行,col 样式指定列. 1. ...

  5. Bzoj2164 采矿(线段树+树链剖分)

    题面 Bzoj 题解 对于每个节点,我们可以用树链剖分和线段树维护以下信息: 单独在某个点分配\(i\)个人的最大收益(可以\(O(m)\)计算) 分配\(i\)的最大收益(可以\(O(m^2)\)计 ...

  6. Java 持久化操作

    持久化就是将内存中的数据保存起来,使之可以长期存在. 在Java中 可以做到持久化有很多种方法. 其中有: 1. 堵塞型IO,也就是我们经常说的io流: 2. 非堵塞型IO,通常称为New IO.也就 ...

  7. shell 统计行数

    语法:wc [选项] 文件… 说明:该命令统计给定文件中的字节数.字数.行数.如果没有给出文件名,则从标准输入读取.wc同时也给出所有指定文件的总统计数.字是由空格字符区分开的最大字符串. 该命令各选 ...

  8. CSS3组件化之菊花loading

    <div class="juhua-loading"> <div class="jh-circle"></div> < ...

  9. [ 原创 ] Java基础7--Java反射机制主要提供了以下哪些功能?

    AVA反射机制主要提供了以下哪些功能? 在运行时判断一个对象所属的类 在运行时构造一个类的对象 在运行时判断一个类所具有的成员变量和方法 在运行时调用一个对象的方法

  10. python opencv3 人脸识别的例子

    一个人脸识别的例子 程序中用到了公共数据集, 欢迎去我的git上下载源码,源码里带有数据集 git:https://github.com/linyi0604/Computer-Vision 脚本中一个 ...