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 ...
随机推荐
- oplog扩容
Oplog的扩容: 背景:一个由3个节点组成的复制集. 主节点:A 从节点:B,C 需求:Oplog扩容,尽量少的影响业务. 思路:先由从节点开始,一台一台的从复制集中剥离,修改,再回归复制集,最后操 ...
- GTK, GTK+, Qt, KDE, GNOME, Unity的区别与联系
GTK,GTK+, Qt是图形界面开发库(GUI Toolkit),用户可以使用这些开发库编写GUI应用,其中GTK+是GTK的升级版. KDE,GNOME,Unity是linux下的桌面环境(Des ...
- JS日期、时间 格式化转换方法
Date.prototype.format = function(fmt) { var o = { "M+" : this.getMonth()+1, //月份 "d+& ...
- ecshop用户中心菜单选项显示内容标签
ecshop用户中心菜单选项有了,那肯定需要给相应的菜单选项添加内容,下面我们主要来讲下调用内容的标签,你也可以先访问一下用户中心菜单选项修改. 用户中心页面的内容分布在两个模板文件中:user_cl ...
- 不定期更新的IDEA功能整理
目录 不定期更新的IDEA功能整理 idea 命令 Preferences 和 Project Structure Keymap HTTP Proxy Postfix Completion 插件 插件 ...
- 快递鸟电子面单打印功能基于java
之前的后天管理系统的电子面单打印使用的是灵通打单. 使用相对比较麻烦,需要到处Excel之后再导入,麻烦. 快递鸟有电子面单api,后台系统直接对接很是方便,不过也遇到了好些问题. 不难是不难,但是遇 ...
- jdk1.8下字符串常量的判断,String.intern()分析
字符串常量池在jdk升级过程中发生了一些变化 在JDK1.6中,它在方法区中,属于“永久代”. 在JDK1.7中,它被移除方法区,放在java堆中. 在JDK1.8中,取消了“永久代”,将常量池放在元 ...
- 利用python实现新浪微博爬虫
第一个模块,模拟登陆sina微博,创建weiboLogin.py文件,输入以下代码: #! /usr/bin/env python # -*- coding: utf-8 -*- import sys ...
- BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)
题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...
- 【漏洞预警】Apache ActiveMQ Fileserver远程代码执行漏洞(CVE-2016-3088)
漏洞编码:CVE-2016-3088 实验环境:Linux Apache ActiveMQ版本号:Apache ActiveMQ 5.7.0 ----------------------------- ...