android面试Recycleview相关

737 阅读6分钟

recycleview

  • 1.RecyclerView的多级缓存机制,每一级缓存具体作用是什么,分别在什么场景下会用到哪些缓存

第一级缓存 mAttachedScrap mChangedScrap,

scrap是用来保存被rv移除掉但最近又马上要使用的缓存,比如说rv中自带item的动画效果。 稍微仔细看的话就能发现scrap缓存有两个成员mChangedScrap和mAttachedScrap,它们保存的对象有些不一样,一般调用adapter的notifyItemRangeChanged被移除的viewholder会保存到mChangedScrap,其余的notify系列方法(不包括notifyDataSetChanged)移除的viewholder会被保存到mAttachedScrap中。 使用场景就是RecyclerView滚动时、还有在可见范围内删除Item后用notifyItemRemoved方法通知更新时;

第二级缓存 mCachedViews

也是rv中非常重要的一个缓存,就linearlayoutmanager来说cached缓存默认大小为2,它的容量非常小,所起到的作用就是rv滑动时刚被移出屏幕的viewholer的收容所。

因为rv会认为刚被移出屏幕的viewholder可能接下来马上就会使用到,所以不会立即设置为无效viewholer,会将它们保存到cached中,但又不能将所有移除屏幕的viewholder都视为有效viewholer,所以它的默认容量只有2个 ViewHolder数据还在,只有原来的position可用,不需要重新绑定数据\

第三级缓存 mViewCacheExtension

第三级缓存,这是一个自定义的缓存,没错rv是可以自定义缓存行为的,在这里你可以决定缓存的保存逻辑,但是这么个自定义缓存一般都没有见过具体的使用场景,而且自定义缓存需要你对rv中的源码非常熟悉才行,否则在rv执行item动画,或者执行notify的一系列方法后你的自定义缓存是否还能有效就是一个值得考虑的问题。

所以一般不太推荐使用该缓存,更多的我觉得这可能是google自已留着方便扩展来使用的,目前来说这还只是个空实现而已,从这点来看其实rv所说的四级缓存本质上还只是三级缓存。

第四级缓存 mRecyclerPool

这个缓存保存的对象就是那些无效的viewholer,虽说无效的viewholer上的数据是无效的,但是它的rootview还是可以拿来使用的,这也是为什么最早的listview有一个convertView参数的原因,当然这种机制也被rv很好的继承了下来。

pool一般会和cached配合使用,这么来说,cached存不下的会被保存到pool中毕竟cached默认容量大小只有2,但是pool容量也是有限的当保存满之后再有viewholder到来的话就只能会无情抛弃掉,它也有一个默认的容量大小

privatestaticfinalintDEFAULT_MAX_SCRAP = 5;

ViewHolder数据重置,需要重新绑定数据

2.RecyclerView的滑动回收复用机制

mCachedViews: 这个就重要得多了,滑动过程中的回收和复用都是先处理的这个 List,这个集合里存的 ViewHolder 的原本数据信息都在,所以可以直接添加到 RecyclerView 中显示,不需要再次重新 onBindViewHolder()。

mRecyclerPool: 这个也很重要,但存在这里的 ViewHolder 的数据信息会被重置掉,相当于 ViewHolder 是一个重创新建的一样,所以需要重新调用 onBindViewHolder 来绑定数据。

RecyclerView 滑动场景下的回收复用涉及到的结构体两个:
mCachedViews 和 RecyclerViewPool

复用流程:2级缓存 mCachedViews 取 > 1级缓存 RecycledViewPool 取 > Adapter.onCreateViewHolder()

回收流程:遍历移除屏幕的 View,从 View的 LayoutParams 中取出 ViewHolder,塞入 2级缓存 mCachedViews
如果 mCachedViews 满了(容量2),则 mCachedViews 移除第一个,用来放要回收的 ViewHolder
如果 RecycledViewPool 对应 viewType 的 List 没满(容量5),则从 mCachedViews 移除的 ViewHolder 放入 RecycledViewPool。

在 ViewPool 里的 ViewHolder 都是跟全新的 ViewHolder 一样,只要 type 一样,有找到,就可以拿出来复用,重新绑定下数据即可。

  • 3.RecyclerView的刷新回收复用机制 使用的 mAttachedScrap mChangedScrap

  • 4.RecyclerView 为什么要预布局

列表中有两个表项(1、2),删除 2,此时 3 会从屏幕底部平滑地移入并占据原来 2 的位置。

这是怎么做到的?RecyclerView如何知道表项 3 的动画轨迹?虽然动画的终点已经有了(表项 2 的顶部),那起点呢?LayoutManager只加载所有可见表项,在删除表项 2 之前,表项 3 处于不可见状态,它并不会被 layout。

对于这种情况RecyclerView的策略是“执行两次 layout”:为动画前的表项先执行一次pre-layout,将不可见的表项 3 也加载到布局中,形成一张布局快照(1、2、3)。再为动画后的表项执行一次post-layout,同样形成一张布局快照(1、3)。比对两张快照中表项 3 的位置,就知道它该如何做动画了

RecyclerView为了实现表项动画,进行了 2 次布局,第一次预布局,第二次正真的布局,在源码上表现为LayoutManager.onLayoutChildren()被调用 2 次

第一次布局时,并不会触发pre-layout。pre-layout只会在每次notify change时才会被触发,目的是通过saveOldPosition方法将屏幕中各位置上的ViewHolder的坐标记录下来,并在重新布局之后,通过对比实现Item的动画效果

5.ListView 与 RecyclerView区别

RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。 RecyclerView的优势在于a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.客观来说,RecyclerView在特定场景下对ListView的缓存机制做了补强和完善。

  1. 缓存不同:

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

5.RecyclerView性能优化

www.jianshu.com/p/1853ff1e8…