ListView与RecyclerView对比浅析——缓存机制

https://www.jianshu.com/p/193fb966e954

一,背景

RecyclerView是谷歌官方出的一个用于大量数据展示的新控件,可以用来代替传统的ListView,更加强大和灵活。

最近,自己负责的业务,也遇到这样的一个问题,关于是否要将ListView替换为RecyclerView?

秉承着实事求是的作风,弄清楚RecyclerView是否有足够的吸引力替换掉ListView,我从性能这一角度出发,研究RecyclerView和ListView二者的缓存机制,并得到了一些较有益的”结论”,待我慢慢道来。

同时也希望能通过本文,让大家快速了解RecyclerView与ListView在缓存机制上的一些区别,在使用上也更加得心应手吧。

PS:相关知识: ListView与RecyclerView缓存机制原理大致相似,如下图所示:

过程中,离屏的ItemView即被回收至缓存,入屏的ItemView则会优先从缓存中获取,只是ListView与RecyclerView的实现细节有差异.(这只是缓存使用的其中一个场景,还有如刷新等)

PPS:本文不贴出详细代码,结合源码食用更佳!

二. 正文

2.1 缓存机制对比

  1. 层级不同:

    RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。

    具体来说: ListView(两级缓存):

    RecyclerView(四级缓存):

    ListView和RecyclerView缓存机制基本一致:

    1). mActiveViews和mAttachedScrap功能相似,意义在于快速重用屏幕上可见的列表项ItemView,而不需要重新createView和bindView;

    2). mScrapView和mCachedViews + mReyclerViewPool功能相似,意义在于缓存离开屏幕的ItemView,目的是让即将进入屏幕的ItemView重用.

    3). RecyclerView的优势在于a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.客观来说,RecyclerView在特定场景下对ListView的缓存机制做了补强和完善。

  2. 缓存不同:

    1). RecyclerView缓存RecyclerView.ViewHolder,抽象可理解为: View + ViewHolder(避免每次createView时调用findViewById) + flag(标识状态); 2). ListView缓存View。

    缓存不同,二者在缓存的使用上也略有差别,具体来说: ListView获取缓存的流程:

    RecyclerView获取缓存的流程:

    1). RecyclerView中mCacheViews(屏幕外)获取缓存时,是通过匹配pos获取目标位置的缓存,这样做的好处是,当数据源数据不变的情况下,无须重新bindView:

    而同样是离屏缓存,ListView从mScrapViews根据pos获取相应的缓存,但是并没有直接使用,而是重新getView(即必定会重新bindView),相关代码如下:

//AbsListView源码:line2345
//通过匹配pos从mScrapView中获取缓存
final View scrapView = mRecycler.getScrapView(position);
//无论是否成功都直接调用getView,导致必定会调用createView
final View child = mAdapter.getView(position, scrapView, this);
if (scrapView != null) {
    if (child != scrapView) {
        mRecycler.addScrapView(scrapView, position);
    } else {
        ...
    }
}

2). ListView中通过pos获取的是view,即pos–>view; RecyclerView中通过pos获取的是viewholder,即pos –> (view,viewHolder,flag); 从流程图中可以看出,标志flag的作用是判断view是否需要重新bindView,这也是RecyclerView实现局部刷新的一个核心.

2.2 局部刷新

由上文可知,RecyclerView的缓存机制确实更加完善,但还不算质的变化,RecyclerView更大的亮点在于提供了局部刷新的接口,通过局部刷新,就能避免调用许多无用的bindView.

(RecyclerView和ListView添加,移除Item效果对比)

结合RecyclerView的缓存机制,看看局部刷新是如何实现的: 以RecyclerView中notifyItemRemoved(1)为例,最终会调用requestLayout(),使整个RecyclerView重新绘制,过程为: onMeasure()–>onLayout()–>onDraw()

其中,onLayout()为重点,分为三步: 1. dispathLayoutStep1():记录RecyclerView刷新前列表项ItemView的各种信息,如Top,Left,Bottom,Right,用于动画的相关计算; 2. dispathLayoutStep2():真正测量布局大小,位置,核心函数为layoutChildren(); 3. dispathLayoutStep3():计算布局前后各个ItemView的状态,如Remove,Add,Move,Update等,如有必要执行相应的动画.

其中,layoutChildren()流程图:

当调用notifyItemRemoved时,会对屏幕内ItemView做预处理,修改ItemView相应的pos以及flag(流程图中红色部分):

当调用fill()中RecyclerView.getViewForPosition(pos)时,RecyclerView通过对pos和flag的预处理,使得bindview只调用一次.

需要指出,ListView和RecyclerView最大的区别在于数据源改变时的缓存的处理逻辑,ListView是”一锅端”,将所有的mActiveViews都移入了二级缓存mScrapViews,而RecyclerView则是更加灵活地对每个View修改标志位,区分是否重新bindView。

三.结论

在一些场景下,如界面初始化,滑动等,ListView和RecyclerView都能很好地工作,两者并没有很大的差异:

文章的开头便抛出了这样一个问题,微信Android客户端卡券模块,大部分UI都是以列表页的形式展示,实现方式为ListView,是否有必要将其替换成RecyclerView呢?

答案是否定的,从性能上看,RecyclerView并没有带来显著的提升,不需要频繁更新,暂不支持用动画,意味着RecyclerView优势也不太明显,没有太大的吸引力,ListView已经能很好地满足业务需求。

数据源频繁更新的场景,如弹幕:http://www.jianshu.com/p/2232a63442d6等RecyclerView的优势会非常明显;

进一步来讲,结论是: 列表页展示界面,需要支持动画,或者频繁更新,局部刷新,建议使用RecyclerView,更加强大完善,易扩展;其它情况(如微信卡包列表页)两者都OK,但ListView在使用上会更加方便,快捷。

四.参考资料

      1. ListView

        a. android-23源码  b. Android ListView工作原理解析,带你从源码的角度彻底理解:http://blog.csdn.net/guolin_blog/article/details/44996879   c. android自己动手写ListView学习其原理:http://blog.csdn.net/androiddevelop/article/details/8734255

      2. RecyclerView

        a. RecyclerView-v7-23.4.0源码   b. RecyclerView剖析:http://blog.csdn.net/qq_23012315/article/details/50807224   c. RecyclerView剖析:http://blog.csdn.net/qq_23012315/article/details/51096696

作者:庞哈哈哈12138
链接:https://www.jianshu.com/p/193fb966e954
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

原文地址:https://www.cnblogs.com/wytiger/p/10415402.html

时间: 2024-10-01 11:57:16

ListView与RecyclerView对比浅析——缓存机制的相关文章

从 ListView 到 RecyclerView 的用法浅析

文章目录 要走好明天的路,必须记住昨天走过的路,思索今天正在走着的路. ListView,一种在垂直滚动列表中显示条目的视图:RecyclerView,一种在局限的窗口呈现大数据集合的灵活视图.RecyclerView 部件是 ListView 的一种更高级且更灵活的版本. 以上描述来自官网. 移动设备屏幕空间有限,导致在屏幕上一次性显示的内容也是有限的.当需要显示大量的数据时,设想有这样的控件,可以帮助用户只通过手指上下滑动,就可以让屏幕外的数据滚动到屏幕内,同时,屏幕上原有的数据会滚动出屏幕

关于RecyclerView中Viewholder和View的缓存机制的探究

这个题目放在草稿箱里面许久了,一直没有动力提笔.趁现在公司人还没有来齐,工作量还不是很大,就挤出来时间来把它完善了. 我们知道,RecyclerView是经典的ListView的进化与升华,它比ListView更加灵活,但也因此引入了一定的复杂性.最新的v7支持包新添加了RecyclerView. 我们知道,ListView通过使用ViewHolder来提升性能.ViewHolder通过保存item中使用到的控件的引用来减少findViewById的调用,以此使ListView滑动得更加顺畅.但

浏览器缓存机制浅析

非HTTP协议定义的缓存机制 浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires: Cache-control等).但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的<head>节点中加入<meta>标签,代码如下: <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> 上述代码的作用是告诉浏览器当前页面不被缓存,每

ListView的缓存机制

说到ListView当然少不了Adapter了,Adapter的作用就是ListView界面与数据之间的桥梁,当列表里的每一项显示到页面的额时候,都会调用Adapter的getView()这个方法返回一个View.这样,ListView中有多少项,就应该调用多少次getView()方法去绘制每一项的界面.如果项数少的时候(几十行),这是没问题的.但是如果有一万行,一百万行,那么就会出现问题了,它会占用系统极大的内存,所以必须采用性能优化的方法. 先说一下ListView的工作原理:ListVie

H5缓存机制浅析-移动端Web加载性能优化【干货】

转载:H5缓存机制浅析-移动端Web加载性能优化[干货] 作者:贺辉超,腾讯游戏平台与社区产品部 高级工程师 目录 1 H5缓存机制介绍 2 H5缓存机制原理分析 2.1 浏览器缓存机制 2.2 Dom Storgage(Web Storage)存储机制 2.3 Web SQL Database存储机制 2.4 Application Cache(AppCache)机制 2.5 Indexed Database (IndexedDB) 2.6 File System API 3 移动端Web加载

Android笔记(二十五) ListView的缓存机制与BaseAdapter

之前接触了ListView和Adapter,Adapter将数据源和View连接起来,实际应用中,我们要显示的数据往往有很多,而屏幕只有那么大,系统只能屏幕所能显示的内容,当我们滑动屏幕,会将旧的内容放入到缓冲池中,再从缓存池中拿出新的内容显示出来,这就是ListView的缓存机制,这一机制可以极大的节省系统资源. BaseAdapter BaseAdapter通常用于被扩展,扩展BaseAdapter可以对各项列表进行最大限度的定制. 我们可以用自己的类去继承BaseAdapter,然后实现g

自己定制ListView,上拉刷新和下拉刷新,加载网络图片,并且添加缓存机制。

1 package com.lixu.listviewrefresh; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 import java.util.Random; 6 7 import com.lixu.listviewrefresh.Loadnetimage.OnLoadnetimageListener; 8 import com.lixu.listviewrefresh.MyRefreshListview.On

android:ListView缓存机制及BaseAdapter的三重境界(逗比式,普通式,文艺式)

大家都知道listview的格式是一定的 而数据源确是多重多样的 这时候 就需要一种适配器来把数据源转换成listview要显示的格式 baseAdapter就诞生了. listview和gridView的显示和缓存机制 如下图 大家都知道屏幕的大小是有限的 可是listview中的数据却可能很多 所以手机不能一下子展示所有的数据 它只会加载屏幕上显示的数据 . 如上图,当我们把屏幕往下滑动时 item1回收到recycler 而item8要显示在屏幕上 item8从recycler取出这样一个

Android之ListView异步加载网络图片(优化缓存机制)【转】

网上关于这个方面的文章也不少,基本的思路是线程+缓存来解决.下面提出一些优化: 1.采用线程池 2.内存缓存+文件缓存 3.内存缓存中网上很多是采用SoftReference来防止堆溢出,这儿严格限制只能使用最大JVM内存的1/4 4.对下载的图片进行按比例缩放,以减少内存的消耗 具体的代码里面说明.先放上内存缓存类的代码MemoryCache.java: public class MemoryCache { private static final String TAG = "MemoryCa