资讯专栏INFORMATION COLUMN

【腾讯Bugly干货分享】Android ListView与RecyclerView对比浅析--缓存

kun_jian / 2855人阅读

摘要:数据源频繁更新的场景,如弹幕等的优势会非常明显进一步来讲,结论是列表页展示界面,需要支持动画,或者频繁更新,局部刷新,建议使用,更加强大完善,易扩展其它情况如微信卡包列表页两者都,但在使用上会更加方便,快捷。

本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d...

作者:黄宁源

一,背景

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()为重点,分为三步:

dispathLayoutStep1():记录RecyclerView刷新前列表项ItemView的各种信息,如Top,Left,Bottom,Right,用于动画的相关计算;

dispathLayoutStep2():真正测量布局大小,位置,核心函数为layoutChildren();

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/2232...等RecyclerView的优势会非常明显;

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

Ps:仅从一个角度做了对比,盲人摸象,有误跪求指正。

四.参考资料 1. ListView

Android-23源码

Android ListView工作原理解析,带你从源码的角度彻底理解:http://blog.csdn.net/guolin_b...

Android自己动手写ListView学习其原理:http://blog.csdn.net/androidd...

2. RecyclerView

RecyclerView-v7-23.4.0源码

RecyclerView剖析:http://blog.csdn.net/qq_23012...

RecyclerView剖析:http://blog.csdn.net/qq_23012...


更多精彩内容欢迎关注bugly的微信公众账号:

腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/13305.html

相关文章

  • 腾讯Bugly干货分享Android ListViewRecyclerView对比浅析--缓存

    摘要:数据源频繁更新的场景,如弹幕等的优势会非常明显进一步来讲,结论是列表页展示界面,需要支持动画,或者频繁更新,局部刷新,建议使用,更加强大完善,易扩展其它情况如微信卡包列表页两者都,但在使用上会更加方便,快捷。 本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d... 作者:黄宁源 一,背景 RecyclerV...

    wangzy2019 评论0 收藏0
  • 博客 - 收藏集 - 掘金

    摘要:技术之类加载机制掘金类加载机制是语言的一大亮点,使得类可以被动态加载到虚拟机中。玩转仿探探卡片式滑动效果掘金讲起本篇博客的历史起源,估计有一段历史了。 Java 技术之类加载机制 - Android - 掘金类加载机制是 Java 语言的一大亮点,使得 Java 类可以被动态加载到 Java 虚拟机中。 这次我们抛开术语和概念,从例子入手,由浅入深地讲解 Java 的类加载机制。 本文...

    Shimmer 评论0 收藏0
  • 博客 - 收藏集 - 掘金

    摘要:技术之类加载机制掘金类加载机制是语言的一大亮点,使得类可以被动态加载到虚拟机中。玩转仿探探卡片式滑动效果掘金讲起本篇博客的历史起源,估计有一段历史了。 Java 技术之类加载机制 - Android - 掘金类加载机制是 Java 语言的一大亮点,使得 Java 类可以被动态加载到 Java 虚拟机中。 这次我们抛开术语和概念,从例子入手,由浅入深地讲解 Java 的类加载机制。 本文...

    The question 评论0 收藏0
  • 界面工具 - 收藏集 - 掘金

    摘要:上列表左右滑动开源组件掘金是一款用于为上的排布提供左滑右滑操作的库。这里我贴出最终的兼容方案教你用两层嵌套实现三级展示界面掘金最近项目中使用一个三级展示列表,要求第一级和第二季都可以折叠,并有不同的图标变换,第三层展示数据,可点击。 八年 Android 开发,看我如何简化 Android 的 UI 开发! - Android - 掘金作者 : Super Mary 校对者: Zhao...

    wuaiqiu 评论0 收藏0
  • 腾讯Bugly干货分享】React Native项目实战总结

    摘要:本文来自于腾讯开发者社区,非经作者同意,请勿转载,原文地址小时内拼工作,小时外拼成长这是大家共同的理想。每周都会举行嘉宾分享,话题讨论等活动。上一期我们邀请了腾讯工程师王少鸣分享了项目实战总结。 本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/577e16a7640ad7b4682c64a7 8小时内拼工作,8小时外...

    张利勇 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<