Listview与RecyclerView对比浅析【重点对比缓存】

RecyclerView和ListView都是用于加载大量数据的控件,RecyclerView作为listview的改进加强型,相对于ListView,RecyclerView做出了以下优化:

1.布局效果

ListView 的布局比较单一,只有一个纵向效果;
RecyclerView 的布局效果丰富, 可以在 LayoutMananger 中设置:线性布局(纵向,横向),表格布局,瀑布流布局
在RecyclerView 中,如果存在的 LayoutManager 不能满足需求,可以自定义 LayoutManager

2. Item 点击事件

RecyclerView不支持 item 点击事件,只能用回调接口来设置点击事件
ListView的 item 点击事件直接是setOnItemClickListener

3.局部刷新

在ListView中通常刷新数据是用notifyDataSetChanged() ,但是这种刷新数据是全局刷新的(每个item的数据都会重新加载一遍),这样一来就会非常消耗资源;
RecyclerView中可以实现局部刷新,例如:notifyItemChanged();
如果要在ListView实现局部刷新,依然是可以实现的,当一个item数据刷新时,我们可以在Adapter中,实现一个notifyItemChanged()方法,在方法里面通过这个 item 的 position,刷新这个item的数据

4.动画效果

在RecyclerView中,已经封装好API来实现自己的动画效果;并且如果我们需要实现自己的动画效果,我们可以通过相应的接口实现自定义的动画效果(RecyclerView.ItemAnimator类),然后调用RecyclerView.setItemAnimator() (默认的有SimpleItemAnimator与DefaultItemAnimator);
但是ListView并没有实现动画效果,但我们可以在Adapter自己实现item的动画效果;

5.缓存区别

层级不同

ListView有两级缓存,在屏幕与非屏幕内。mActivityViews + mScrapViews
RecyclerView比ListView多两级缓存:支持开发者自定义缓存处理逻辑,RecyclerViewPool(缓存池)。并且支持多个离屏ItemView缓存(缓存屏幕外2个 itemView)。 mAttachedScrap + mCacheViews + mViewCacheExtension + mRecyclerPool

缓存内容不同

ListView缓存View。
RecyclerView缓存RecyclerView.ViewHolder

RV优势

a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;
b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.

缓存区别

 

1,封装了viewholder,Listview需要自己写ViewHolder缓存,而RecyclerView已经帮我们实现了。
2,RecyclerView的缓存机制有了加强,ListView是2级缓存,而RecyclerView实现了4级缓存。
3,RecyclerView相对于ListView最大的加强是实现了局部刷新,这对于ListView需要刷新全部列表进步很多,特别适用于那些数据源经常发生改变的情况。
下面从缓存机制做出对比:
ListView和RecyclerView的缓存机制大致类似:

过程中,离屏的ItemView即被回收至缓存,入屏的ItemView则会优先从缓存中获取,只是ListView与RecyclerView的实现细节有差异.(这只是缓存使用的其中一个场景,还有如刷新等)。
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(标识状态);

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

2). ListView缓存View。而同样是离屏缓存,ListView从mScrapViews根据pos获取相应的缓存,但是并没有直接使用,而是重新getView(即必定会重新bindView)。

二、 局部刷新

RecyclerView更大的亮点在于提供了局部刷新的接口,通过局部刷新,就能避免调用许多无用的bindView。ListView和RecyclerView最大的区别在于数据源改变时的缓存的处理逻辑,ListView是"一锅端",将所有的mActiveViews都移入了二级缓存mScrapViews,而RecyclerView则是更加灵活地对每个View修改标志位,区分是否重新bindView。

ListView获取缓存的流程:

 

RecyclerView获取缓存的流程:

 

结合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只调用一次.



作者:卫宫士郎
链接:https://www.jianshu.com/p/257c279a3493  https://juejin.cn/post/6844904020918665223
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值