RecyclerView源码分析(一)--整体设计
RecyclerView这个控件出来已经有一段时间了,如果看这篇文章的你,还没有使用过这个控件。那请先去学习怎样使用。不然看也白看。这里奉上一些关于介绍RecyclerView使用方法的优秀博客:
- 鸿洋大神的 Android RecyclerView 使用完全解析 体验艺术般的控件这篇文章详细介绍了RecyclerView的基本使用方法,没有用过的照着敲一遍应该就算是入门了。
- 鸿洋大神的 为RecyclerView打造通用Adapter 让RecyclerView更加好用这篇是鸿洋大神对RecyclerView的封装,建议使用熟练了再来使用这个,不然很容易忘记原本的代码应该怎样写。
- D_clock爱吃葱花的 RecyclerView 和 ListView 使用对比分析这个文章其实是一个RecyclerView的总结。只不过是通过与ListView对比来的,对于熟悉ListView的Coder入手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?个人拙见有以下几点:
- 布局
- 动画
- 装饰
这些大家基本也都知道。那么我们分别看它在每个功能点上面的设计:
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的内部结构。
- Recycler里有几个ViewHolder的容器,用来存储不同状态的ViewHolder,以便之后复用。其中ViewCacheExtension类,是用户可以自定义复用机制的类。
- RecyclerViewPool,这个可以从外部对多个RecyclerView设置同一个RecyclerViewPool,从而实现多个RecyclerView中的ViewHolder的复用。
总结
本章简单的介绍了RecyclerView内部设计的大体框架结构。接下来会详细的介绍主要流程和机制。整理源码很费体力,如果这篇文章让你有所收获,请不要吝惜你的喜欢,你的喜欢是我写作的动力。
作者:柴泽建_Jack
链接:https://www.jianshu.com/p/9ddfdffee5d3
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
RecyclerView源码分析(一)--整体设计的更多相关文章
- RecyclerView 源码分析(二) —— 缓存机制
在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ...
- ibatis源码学习1_整体设计和核心流程
背景介绍ibatis实现之前,先来看一段jdbc代码: Class.forName("com.mysql.jdbc.Driver"); String url = "jdb ...
- [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构
[阿里DIN] 深度兴趣网络源码分析 之 整体代码结构 目录 [阿里DIN] 深度兴趣网络源码分析 之 整体代码结构 0x00 摘要 0x01 文件简介 0x02 总体架构 0x03 总体代码 0x0 ...
- RecyclerView 源码分析(一) —— 绘制流程解析
概述 对于 RecyclerView 是那么熟悉又那么陌生.熟悉是因为作为一名 Android 开发者,RecyclerView 是经常会在项目里面用到的,陌生是因为只是知道怎么用,但是却不知道 Re ...
- Duilib源码分析(六)整体流程
在<Duilib源码分析(一)整体框架>.<Duilib源码分析(二)控件构造器—CDialogBuilder>以及<Duilib源码分析(三)XML解析器—CMarku ...
- Duilib源码分析(一)整体框架
Duilib界面库是一款由杭州月牙儿网络技术有限公司开发的界面开源库,以viksoe项目下的UiLib库的基础上开发(此后也将对UiLib库进行源码分析):通过XML布局界面,将用户界面和处理逻辑彻底 ...
- 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计
问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...
- jQuery 2.0.3 源码分析core - 整体架构
拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery ...
- Sizzle源码分析:一 设计思路
一.前言 DOM选择器(Sizzle)是jQuery框架中非常重要的一部分,在H5还没有流行起来的时候,jQuery为我们提供了一个简洁,方便,高效的DOM操作模式,成为那个时代的经典.虽然现在Vue ...
随机推荐
- CCF CSP 201604-2 俄罗斯方块
CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201604-2 俄罗斯方块 问题描述 俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游 ...
- Proxy 代理
意图 为其他对象提供一种代理以控制对这个对象的访问 动机 对一个对象进行访问控制的原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化 典型例子:智能指针的实现,通过引用计数来决定“=” 复制 ...
- Java I/O流输入输出,序列化,NIO,NIO.2
Java IO流 File类: File类是java.io包下代表和平台无关的文件和目录,File不能访问文件内容本身. File类基本操作: System.out.println("判断文 ...
- 同步VDP时间
使用yast 进入蓝屏界面,修改system—date and time,取消hardware clock set to utc,时区设置为上海或者北京,然后sntp -r 时间服务器地址 敲击syn ...
- tftp协议
<前言> 嵌入式开发是一个交叉开发的模式,需要将宿主机上的文件烧写到目标机上. 方式: JTAG USB 串口 网络 <tftp下载> 首先需要将宿主机架成一个TFTP的服务器 ...
- xml javascript
1.XMLHttpRequest对象 创建XMLHttpRequest对象 xmlhttp=new XMLHttpRequest(); ##老版本的 Internet Explorer (IE5 和 ...
- Windows系统php5.6安装Imagick库
Windows上的安装坑比较多 1.安装Imagick,需要下载6.9.3之下版本的 http://imagemagick.org/script/download.php 官网都是新版本不可以用 我安 ...
- SQLSERVER2014集群实战——IP引发的坑
在之前的帖子里有提到过,为了避免IP变更带来的一系列问题,采取了不改变IP的策略.原以为,只要SQLSERVER的群集IP保持与之前单机部署的IP一致,就基本上不会有问题.然而实际永远比预想的更复杂. ...
- Qt Quick快速入门之线程基础
首先必须明确的是,Qt中的线程使用是相对复杂的,并不像C#中那么随意,特别是结合串口.网络编程等,使用时稍有不慎就会出问题,然后Qt里面经常出了问题就直接崩溃(这个真是谁用谁知道),所以如果在功能上用 ...
- CodeForces600E Lomsat gelral 线段树合并
从树上启发式合并搜出来的题 然而看着好像线段树合并就能解决??? 那么就用线段树合并解决吧 维护\(max, sum\)表示值域区间中的一个数出现次数的最大值以及所有众数的和即可 复杂度\(O(n \ ...