本文来自于腾讯bugly开发者社区,非经做者赞成,请勿转载,原文地址:http://dev.qq.com/topic/5811d...java
做者:黄宁源android
RecyclerView是谷歌官方出的一个用于大量数据展现的新控件,能够用来代替传统的ListView,更增强大和灵活。缓存
最近,本身负责的业务,也遇到这样的一个问题,关因而否要将ListView替换为RecyclerView?微信
秉承着实事求是的做风,弄清楚RecyclerView是否有足够的吸引力替换掉ListView,我从性能这一角度出发,研究RecyclerView和ListView两者的缓存机制,并获得了一些较有益的"结论",待我慢慢道来。函数
同时也但愿能经过本文,让你们快速了解RecyclerView与ListView在缓存机制上的一些区别,在使用上也更加驾轻就熟吧。工具
PS:相关知识:
ListView与RecyclerView缓存机制原理大体类似,以下图所示:布局
过程当中,离屏的ItemView即被回收至缓存,入屏的ItemView则会优先从缓存中获取,只是ListView与RecyclerView的实现细节有差别.(这只是缓存使用的其中一个场景,还有如刷新等)性能
PPS:本文不贴出详细代码,结合源码食用更佳!学习
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的缓存机制作了补强和完善。
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实现局部刷新的一个核心.
由上文可知,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:仅从一个角度作了对比,盲人摸象,有误跪求指正。
Android-23源码
Android ListView工做原理解析,带你从源码的角度完全理解:http://blog.csdn.net/guolin_b...
Android本身动手写ListView学习其原理:http://blog.csdn.net/androidd...
RecyclerView-v7-23.4.0源码
RecyclerView剖析:http://blog.csdn.net/qq_23012...
RecyclerView剖析:http://blog.csdn.net/qq_23012...
更多精彩内容欢迎关注bugly的微信公众帐号:
腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的状况以及解决方案。智能合并功能帮助开发同窗把天天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同窗定位到出问题的代码行,实时上报能够在发布后快速的了解应用的质量状况,适配最新的 iOS, Android 官方操做系统,鹅厂的工程师都在使用,快来加入咱们吧!