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 列表类控件卡顿优化

1、使用ConstraintLayout减少布局层级。

2、可以的话,设置RecyclerView布局等高,然后设置recyclerView.setHasFixedSize(true)这样可以避免每次绘制Item时,不再重新计算Item高度。

3、根据需求修改RecyclerView默认的绘制缓存选项

 recyclerView.setItemViewCacheSize(20);
 recyclerView.setDrawingCacheEnabled(true);
 recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);

4、在onBindViewHolder/getView方法中,减少逻辑判断,减少临时对象创建。例如:复用事件监听,在其方法外部创建监听,可以避免生成大量的临时变量。
减少逻辑判断参考方案:

    //优化前:
    class MyRecyclerView.Adapter extends RecyclerView.Adapter {

        static final TODAYS_DATE = new Date();
        static final DATE_FORMAT = new SimpleDateFormat("MM dd, yyyy");
        public onBindViewHolder(Task.ViewHolder tvh, int position) {
            Task task = getItem(position);
            if (TODAYS_DATE.compareTo(task.dateDue) > 0) {
                tvh.backgroundView.setColor(Color.GREEN);
            } else {
                tvh.backgroundView.setColor(Color.RED);
            }
            String dueDateFormatted = DATE_FORMAT.format(task.getDateDue());
            tvh.dateTextView.setDate(dueDateFormatted);
        }
    }
    //优化后,改写model
    public class TaskViewModel {
        int overdueColor;
        String dateDue;
    }

    public onBindViewHolder(Task.ViewHolder tvh, int position) {    
        TaskViewModel taskViewModel = getItem(position);
        tvh.backgroundView.setColor(taskViewModel.getOverdueColor());
        tvh.dateTextView.setDate(taskViewModel.getDateDue());
    }

6、避免整个列表的数据更新,只更新受影响的布局。例如,加载更多时,不使用notifyDataSetChanged(),而是使用notifyItemRangeInserted(rangeStart, rangeEnd)

7、scrollingCache=false animationCache=false(针对ListView)
scrollingCache: scrollingCache本质上是drawing cache,你可以让一个View将他自己的drawing保存在cache中(保存为一个bitmap),这样下次再显示View的时候就不用重画了,而是从cache中取出。默认情况下drawing cahce是禁用的,因为它太耗内存了,但是它确实比重画来的更加平滑。而在ListView中,scrollingCache是默认开启的,我们可以手动将它关闭。
animateCache: ListView默认开启了animateCache,这会消耗大量的内存,因此会频繁调用GC,我们可以手动将它关闭掉。

8、对于RecyclerView,持有item具有的独特id,可以很容易地确定具体item并单独更新,当变化发生时,可以按照如下方式更新,从而避免整体刷新:

    adapter.setHasStableIds(true);
    adapter.notifyItemRemoved(position);    
    adapter.notifyItemChanged(position);
    adapter.notifyItemInserted(position);

 

云服务预先定义正确的云计算SLA要求

本文讲的是云服务预先定义正确的云计算SLA要求【IT168评论】云计算服务正在成为主流。他们提供的弹性IT基础设施可对诸如业务增长或新项目等新需求做出快速反应。云计算模式还通过按实际使用付费的方法和规模经济的效应实现可能的成本节省。但是,为了使用云计算模式实现成本节省,IT专业人士们就必须精心制定SLA。

企业依靠服务等级协议(SLA)来要求云计算供应商为所提供的服务提供保障,并在发生服务故障时提出维权主张。例如,SLA明确规定了供应商的责任,例如在什么样的时限内供应商应当能够解决问题,以及发生停机时间和客户失去业务情况下应当由供应商承担的责任。

但是,当谈及云计算SLA时,问题的症结往往在于细节。例如,涉及客户退还的条文就是存在问题的。客户是否应偿还丢失的服务,或者SLA中是否已规定了未来的信贷?一点都不奇怪,为供应商和用户双方建立一个可靠、实际可行且都同意的SLA是一个相当复杂的任务。因此,公司在面对这些精美打印的文档时,都显得那么的谨小慎微。

对于跃跃欲试涉水云计算服务的公司来说,他们应审慎考虑潜在的风险,其中包括在选择云计算服务供应商时涉及的定价、供应商责任、可用性、数据安全性、客户权利、风险以及处罚等问题。

准备一个云计算SLA

当你在合同签名栏上签名之前,你必须确定你的应用有一定的业务需求。除非你可以确定你的*长停机允许时间和你公司的潜在业务损失,否则你无法指定云计算供应商用于备份和运行灾难恢复所需的时间。这意味着需要运行场景和数字支持。

首先,确定云计算环境中与关键业务需求相关的数据和应用程序。这就要求建立关键性能指标(KPI),对于你公司业务需求来说,那是特有的,例如:

• 可接受延迟水平

• 停机或数据丢失的可度量影响,

• 经常访问业务数据(包括当前的或已归档的)的需求

• 一个云计算服务使用模式。

如果一个企业需要使用一个云计算服务,同时在每月、每季度或每年的某些时候会发生高峰业务负载,那么供应商所提供SLA中的每月平均延迟的指标数字并不能说明供应商是否能够得到满足你的业务延迟需求。同时,理解业务需求也是很重要的,其中包括合法性、合规性、监管或其他与关键业务相关的责任,这些也是公司用户所应当坚持的。这些因素可能涉及数据位置、数据集大小、访问速度或用于访问已归档/备份数据的时间。

相关考虑还应当包括灾难恢复、可用性保证、隐私、完全删除、加密,以及用于监控、管理和审查云计算SLA的能力。我们用一个示例来说明,你的公司可能出于法律或法规的原因需要把相关数据在物理上存储在某一具有地域限制的范围内,但是你的服务供应商又是一家全球性实体公司,出于经济型考虑其麾下的数据中心遍及多个不同国家。在这种情况下,你需要确保供应商SLA不仅能够解决你的数据位置需求,而且还应规定必要的数据访问审查功能。

供应商的方法也是另一个应予以考虑的因素。一个具有前瞻性眼光的云计算供应商应当能够演示某些*佳方法以确保合规性要求。作为一个中立的第三方,它应当能够为职责分离提供证据,并为关键业务信息提供监管链以支持合规性的一致性。

在外包或合作外包的云计算环境中,评估服务等级协议应当非常清楚地了解与SLA矛盾或发生违反的影响,以及相关的解决问题的程序。典型的商用云计算SLA可能并无法满足企业用户对关键业务数据的需求。

设定云计算供应商和消费者的责任

在你评估你的业务需求之后,你可以从云计算服务供应商的角度出发来考虑这些需求。在发生停机事件或问题时,你的公司和供应商之间应当如何来分担责任?供应商的透明度水平如何,它是否能够主动地向客户告知SLA中的非合规和违反条款信息?在发生灾难事件时,是否有条款限制供应商对你公司的数据承担责任?在面对灾难事件时,供应商应提供什么类型的灾难恢复?

这些问题的答案可能会令人感到相当的诧异。虽然你可以抱有幻想,但是我不得不告知,在发生故障时举证责任往往并不是由供应商一方来承担的。有可能需要客户来确定服务故障以及相关不良影响。

除非在其内部或私有云计算设置中已有SLA自动违规识别功能,该功能可以很容易地被扩展并应用于混合云计算,否则对云计算服务进行监控和管理可能会导致公司必须承担额外的工作和成本。公司还应对违规处罚做出评估,以确定这些处罚条款已合理地涵盖所有丢失业务机会的情况。

一家优秀的云服务提供商,需要具备哪些条件

对正考虑采用云服务的公司来说,一个重要的问题是“一家优秀的云服务提供商具备哪些特质?”基本的答案往往包括:成本低、适合客户的应用程序模式以及切合实际的服务水平协议(SLA)。但是这些答案在云服务市场已成了*低要求。这些要素不足以将“优秀”或者甚至“出色”的云服务提供商与其他云服务提供商区别开来。往云服务投入大笔IT预算的企业在加大投入之前,需要具体的方法来区别云服务提供商。

一家优秀的云服务提供商应具备哪些条件,具体如下:

一、拥有一定的行业专长和规模。

云服务客户列出的*重要的指标之一是,他们想要在市场上证明已取得了成功的云计算服务提供商。许多企业寻找推荐客户、有文档说明的应用程序,有时甚至是描述如何为云环境开发一组特定的应用程序或将其迁移到云环境的蓝图。许多中小企业常常本身缺少大企业那样的云服务技能,因而希望云服务提供商在规划、小规模测试和云服务部署方面给予支持。中小企业寻找开展云服务项目时出力更多的提供商,声称云计算服务提供商可以比集成商更省钱、更可靠。

二、支持云服务建模和测试。

大大小小的公司都需要列出采用云计算服务的正当理由;它们应该明白应用程序使用情况和数据存储需求方面的差异会给云计算服务价格带来怎样的影响。如果企业的云应用程序比较复杂,涉及资源弹性部署、转移区域重心或者故障切换和负载均衡,它们想知道云服务在所有可能的负载和故障模式下性能将如何。这是小规模测试所无法告诉你的,所以建模工作至关重要。虽然客户并不坚持要求云服务提供商本身拥有建模工具,但是他们的确希望在接触云计算服务建模公司和工具方面有经验的提供商。

三、能够熟练地构建和部署混合云应用程序。

对故障切换和负载均衡应用程序有兴趣,这表明了需要下一个差异化优势:混合云计算。除非内部的IT资源能够与云服务主机托管协调一致——这对溢出和备份应用程序来说至关重要,否则大多数公司不会考虑采用云服务。这些公司指望从公共云服务提供商处获得忠告,了解如何运用内部虚拟化和多程序设计/SOA(面向服务的架构)主机等,构建混合应用程序。这常常需要提供商确定与自己的公共云计算服务顺利协同运行的私有云“堆栈”。

四、提供面向公共云和私有云的管理工具。

复杂的公共云和混合云应用程序促使客户需要管理工具,以便有助于将应用程序连接到云环境,以及将应用程序部署到云环境。公共云服务的早期采用者致力于管理界面。不过,越来越多测试云服务的大多数公司发现,管理界面的重要性不如与公共云计算和私有云计算兼容、管理和界面功能兼具的一般性配置和支持工具包。一些厂商把这些工具包作为“模板”或“框架”来提供。开源项目能够以一种灵活的、与提供商独立的方式来处理云应用程序配置问题。

五、愿意开发和运行小规模测试。

很少有公司没有在云计算环境测试自己的应用程序,就准备在云服务方面投入大笔资金。问题在于,要是不能在一定程度上保证成功,就很难证明有必要投入小规模测试本身所需的成本。云服务提供商应该与公司客户一起制定小规模测试计划,以便随着对项目的信心越来越强,可以降低风险,逐渐增加云服务费。

具备上述所有特质的云计算服务提供商是大有助益的合作伙伴;要是某一家云服务提供商无法承诺保证具有这些特质,就会带来比较大的风险。这些特质从另一侧面表明了影响云计算应用程序部署的一些问题,所以所有云服务提供商都理应具备这些特质。

小白用户选择阿里云服务器过程中的注意事项 新手必看

很多小白用户在选择阿里云服务器时,往往对于服务器的规格、配置、带宽等不知道怎么选是适合自己的,那么说在选择过程中,规格、带宽、镜像、安全组、时长都是有需要注意的地方,下面我分享这些需要注意的地方。

一、注册阿里云账号并做实名认证

账号注册好之后,*步不是去买阿里云的产品,而是要先做实名认证。
参考资料:
1.个人实名认证
2.企业实名认证 在上面页面中能看到

二、选择云服务器配置

首先要选服务器地域和实例规格,实例规格是初次买*不容易选择的,低无法满足业务需求,高了会造成云服务器资源浪费,还有投入成本。
注意事项:
1.服务器地域选择,就是选择的服务器所在地理位置,选择距离自己网站目标客户较近的地域可以提高访问速度,例如主要面对华北的客户,那么选择华北1的北京、青岛机房比较好,南方用户选择华南和华东地域比较好。
2.实例规格选择,左侧有场景配置选型,我们可以点开看下官方的推荐,或者可以按照目前云计算当中比较流行的配置方案:
①:普通的个人小型网站,个人博客等小流量网站
可选择低配置的共享型服务器或者 t5机型
推荐配置:CPU:1核、内存2G、硬盘40G、带宽:1M或2M
②:论坛、门户类网站
论坛、门户类网站,用户活跃性与访问量较高,需要有足够的服务器资源空间和带宽,提升访问速度。
推荐配置:CPU:2核、内存:4G、硬盘200-500G、带宽:5-10M
③:品牌官网类网站
对官网、品牌较为重视的政府、企业等, 需要保证网站浏览更加流利顺畅,提升政府、品牌形象。
推荐配置:CPU:4核、内存:8G、硬盘150G、带宽:5M
④:视频、购物类网站:视频、购物类网站
包含庞大的数据信息, 需要保证迅速的信息处理能力保证网站的点播、交易正常进行。
推荐配置:CPU:8核、内存:16G、硬盘300G以上、带宽:10M以上
⑤:游戏、软件类网站
对开发、测试、环境要求较高的游戏软件类网站,需要较高的资源配置带来更强劲的计算性能,保证业务需求。
推荐配置:CPU:16核、内存:32G、硬盘:500G、带宽:10M以上
也可以参考阿里云官方的配置推荐来选择服务器的实例规格
参考资料:
阿里云ECS配置推荐_ 架构推荐

第三:选择镜像,也就是云服务器的操作系统。
注意事项:
1.如果喜欢折腾就选择系统镜像,等买好服务器后,打开服务器就是一个崭新的系统,没有数据。然后你可以自己配置建站环境了。
2.如果不想折腾,也可以在镜像市场选择一个,有免费的,也有付费的,有PHP环境的,也有JAVA环境的,这个镜像会自动安装好功能,免去了手动配置的繁琐,对于不会配置服务器的站长来说,是一个好的选择。

%title插图%num

第四:选择存储,也就是选择云服务器的硬盘大小。

1.系统盘默认40G,一般来说够安装系统使用了。
2.选择增加一块数据盘,这里的数据盘也就是通常电脑上的D盘、E盘、F盘那个意思。根据自己需求考虑吧。如果要达到网站程序或应用数据跟系统盘分离开的目的,就添加一块数据盘。不然就将业务数据也放C盘,如果一旦系统出现故障,就容易导致数据丢失。

第五:选择带宽

可以选择固定带宽或者按使用流量
①固定带宽,如“带宽 1Mbps”。这种就是你的带宽就是固定1Mbps,不管访问人数多少就只有那么多带宽。②按使用流量,就是用多少算多少,要保证账号余额足够,不然欠费后会停到外部访问

注意事项:
1.带宽选择固定带宽模式的较多,前期如果流量低,可以选择小带宽,因为带宽支出是云服务器成本的重要占比。前期小一点能节约成本,后期随着流量的增加,可以增加带宽。
2.如果选择按使用流量,一定要保证账号有余额。
另外云服务器相比传统物理服务器的优势就是包年包月和按量可以互转,用户在后面根据实际情况选择是否更改计费方式。

第六:选择安全组,安全组类似防火墙功能,用于设置网络访问控制。

1.开启80端口和443端口,一个是 http访问,一个是https访问,不然通过域名是访问不了网站的。
2.后期需要增加(或者关闭)更多端口,可以随时更改。
参考资料:安全组规则设置

第七:时长选择

这个直接关系到上云成本。

1.备案网站的服务器时长至少要3个月以上。
2.一般选择按年比较好,不但省去每个月续费的麻烦,同时按年支付,阿里云都会给一定折扣,例如1年85折3年5折等。。