RecyclerView面试必问
Posted 涂程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RecyclerView面试必问相关的知识,希望对你有一定的参考价值。
RecyclerView是谷歌官方出的一个用于大量数据展示的新控件,可以用来代替传统的ListView,更加强大和灵活。
同时也希望能通过本文,让大家快速了解RecyclerView与ListView在缓存机制上的面试。
ListView与RecyclerView缓存机制原理大致相似,如下图所示:
过程中,离屏的ItemView即被回收至缓存,入屏的ItemView则会优先从缓存中获取,只是ListView与RecyclerView的实现细节有差异.(这只是缓存使用的其中一个场景,还有如刷新等)
比较
1.1 缓存机制对比
1.1.1 腾讯面试RecyclerView缓存机制(RecyclerView与ListView有哪几层缓存机制)
RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。
具体来说: ListView(两级缓存):
RecyclerView(四级缓存):
1.1.2 腾讯面试RecyclerView缓存机制(RecyclerView与ListView这几层缓存机制 有什么区别和相同点)
相同点
ListView和RecyclerView缓存机制基本一致:
-
mActiveViews和mAttachedScrap功能相似,意义在于快速重用屏幕上可见的列表项ItemView,而不需要重新createView和bindView;
-
mScrapView和mCachedViews + mReyclerViewPool功能相似,意义在于缓存离开屏幕的ItemView,目的是让即将进入屏幕的ItemView重用.
-
RecyclerView的优势在于a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.客观来说,RecyclerView在特定场景下对ListView的缓存机制做了补强和完善。
不同点
RecyclerView缓存RecyclerView.ViewHolder,抽象可理解为: View + ViewHolder(避免每次createView时调用findViewById) + flag(标识状态);
ListView缓存View。
缓存不同,二者在缓存的使用上也略有差别,具体来说: 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实现局部刷新的一个核心。
1.2缓存局部刷新
1.2.1 字节RecyclerView面试题(RecyclerView的局部刷新讲讲,和ListView区别是什么)
由上文可知,RecyclerView的缓存机制确实更加完善,但还不算质的变化,RecyclerView更大的亮点在于提供了局部刷新的接口,通过局部刷新,就能避免调用许多无用的bindView。
结合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)时,
1.2.2缓存刷新机制总结(ListView和RecyclerView最大的区别在于数据源改变时的缓存的处理逻辑)
RecyclerView通过对pos和flag的预处理,使得bindview只调用一次.
ListView是”一锅端”,将所有的mActiveViews都移入了二级缓存mScrapViews,
而RecyclerView则是更加灵活地对每个View修改标志位,区分是否重新bindView。
1.2.2 字节RecyclerView面试题(相对于ListView RecyclerView 具备哪些优点)
RecyclerView 相比 ListView 在基础使用上的区别主要有如下几点:
ViewHolder 的编写规范化了
RecyclerView 复用 Item 的工作 Google 全帮你搞定,不再需要像 ListView 那样自己调用 setTag
RecyclerView 需要多出一步 LayoutManager 的设置工作
1 更加方便的实现自定义功能
-
android 优雅的为RecyclerView添加HeaderView和FooterView
-
Android 默认提供的 RecyclerView 就能支持 线性布局、网格布局、瀑布流布局 三种 ,而且同时还能够控制横向还是纵向滚动。怎样,从效果上足以碾压 ListView 有木有。
横向滚动的ListView开源控件是不是可以不用再找了?对,你没看错!
瀑布流效果的开源控件是不是可以不用再找了?对,你没看错!
连横向滚动的GridView都不用找了!对,你没看错!
2 自定义LayoutManager
而 LayoutManager 只是一个抽象类而已,系统已经为我们提供了三个相关的实现类:
LinearLayoutManager(线性布局效果)
GridLayoutManager(网格布局效果)
StaggeredGridLayoutManager(瀑布流布局效果)
RecyclerView 基础使用关键点同样有两点:
继承重写 RecyclerView.Adapter 和 RecyclerView.ViewHolder;
设置布局管理器,控制布局效果
系统也为我们提供了两个默认的动画实现:SimpleItemAnimator 和 DefaultItemAnimator。而 RecyclerView 在不手动调用 setItemAnimator 的情况下,则默认用了内置的 DefaultItemAnimator 。
RecyclerView缓存机制总结
主要靠三个内部类来完成,
Recycler
ViewCacheExtension
RecyclerViewPool:
-
首先通过 recycler.getViewForPosition()方法,该方法返回ViewHolder对象,通过源码可以知道,该方法会检查mAttachedScrap和一级缓存列表mCachedViews,如果有则返回ViewHolder进行复用。
-
然后调用ViewCacheExtension.getViewForPositionAndType()方法,注意这个方法是抽象方法,需要开发者进行重写。
-
最后检查RecyclerViewPool是否有ViewHolder。
注意:上述的三个步骤中,只要有一个返回了ViewHolder,就不会在进行后边的步骤了。 最后:缓存的数量:默认的一级缓存中,mCachedViews中可以缓存的ViewHolder的个数是2;默认的缓存池中的缓存数量是 5;所以在缓存时,会先检测一级缓存是否满了,如果没满就add进去,如果满了就加入到三级缓存Recyclerpool
最后
小编在网上收集了一些 Android 开发相关的学习文档、面试题、Android 核心笔记等等文档,希望能帮助到大家学习提升,如有需要学习参考的可以直接去我 GitHub地址:https://github.com/733gh/Android-T3访问查阅。
以上是关于RecyclerView面试必问的主要内容,如果未能解决你的问题,请参考以下文章
Android 开发面试必问知识点 RecyclerView