AndoridAndroid专题

Android ListView与RecyclerView对比浅

2019-03-05  本文已影响55人  萨达哈鲁酱

前言

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

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

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

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


这里写图片描述

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


比较

缓存机制对比

层级不同:

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

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


这里写图片描述

RecyclerView(四级缓存):

这里写图片描述

ListView和RecyclerView缓存机制基本一致

缓存不同:

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

这里写图片描述

RecyclerView获取缓存的流程:

这里写图片描述

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 {
        ...
    }
}

ListView中通过pos获取的是view,即pos-->view;
RecyclerView中通过pos获取的是viewholder,即pos --> (view,viewHolder,flag);

从流程图中可以看出,标志flag的作用是判断view是否需要重新bindView,这也是RecyclerView实现局部刷新的一个核心。

局部刷新

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

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

其中,onLayout()为重点,分为三步:

其中,layoutChildren()流程图:

这里写图片描述
这里写图片描述

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

这里写图片描述

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

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


RecyclerView 优点

RecyclerView 相比 ListView 在基础使用上的区别主要有如下几点:

更加方便的实现自定义功能

Android 优雅的为RecyclerView添加HeaderView和FooterView
Android 默认提供的 RecyclerView 就能支持 线性布局、网格布局、瀑布流布局 三种(这里我们暂且不提代码细节,后文再说),而且同时还能够控制横向还是纵向滚动。怎样,从效果上足以碾压 ListView 有木有。

横向滚动的ListView开源控件是不是可以不用再找了?对,你没看错!
瀑布流效果的开源控件是不是可以不用再找了?对,你没看错!
连横向滚动的GridView都不用找了!对,你没看错!

而 LayoutManager 只是一个抽象类而已,系统已经为我们提供了三个相关的实现类:

RecyclerView 基础使用关键点同样有两点:

系统也为我们提供了两个默认的动画实现:SimpleItemAnimator 和 DefaultItemAnimator。而 RecyclerView 在不手动调用 setItemAnimator 的情况下,则默认用了内置的 DefaultItemAnimator 。

RecyclerView缓存机制总结

主要靠三个内部类来完成,Recycler,ViewCacheExtension,RecyclerViewPool:

注意:上述的三个步骤中,只要有一个返回了ViewHolder,就不会在进行后边的步骤了。
最后:缓存的数量:默认的一级缓存中,mCachedViews中可以缓存的ViewHolder的个数是2;默认的缓存池中的缓存数量是 5;所以在缓存时,会先检测一级缓存是否满了,如果没满就add进去,如果满了就加入到三级缓存Recyclerpool


ListView 优化

如果页面不是复杂,也不是需要太多功能,只需要简单的列表功能,那就可以继续使用ListView, 毕竟实现起来比RecyclerView简单些。

如何优化ListView的性能:


总结

是选择ListView还是RecyclerView 可以根据项目中的功能来的,但是对于他们了解之后的优化也是必要的。

上一篇 下一篇

猜你喜欢

热点阅读