再也不用担心问RecycleView了——面试真题详解
关于RecycleView,之前我写过一篇比较基础的文章,主要说的是缓存和优化等问题。但是有读者反映问题不够实际和深入。于是,我又去淘了一些关于RecycleView的面试真题,大家一起看看吧,这次的问题如果都弄懂了,下次面试再遇到RecycleView应该就没啥可担心的了。
- 讲一下
RecyclerView
的缓存机制,滑动10个,再滑回去,会有几个执行onBindView
。缓存的是什么?cachedView
会执行onBindView吗? RecyclerView
预取机制- 如何实现
RecyclerView
的局部更新,用过payload
吗,notifyItemChange方法中的参数? RecyclerView
嵌套RecyclerView
滑动冲突,NestScrollView嵌套RecyclerView。
讲一下RecyclerView的缓存机制,滑动10个,再滑回去,会有几个执行onBindView。缓存的是什么?cachedView会执行onBindView吗?
RecyclerView预取机制
这两个问题都是关于缓存的,我就一起说了。
1)首先说下RecycleView的缓存结构:
Recycleview有四级缓存,分别是mAttachedScrap(屏幕内),mCacheViews(屏幕外),mViewCacheExtension(自定义缓存),mRecyclerPool(缓存池)
mAttachedScrap(屏幕内)
,用于屏幕内itemview快速重用,不需要重新createView和bindViewmCacheViews(屏幕外)
,保存最近移出屏幕的ViewHolder,包含数据和position信息,复用时必须是相同位置的ViewHolder才能复用,应用场景在那些需要来回滑动的列表中,当往回滑动时,能直接复用ViewHolder数据,不需要重新bindView。mViewCacheExtension(自定义缓存)
,不直接使用,需要用户自定义实现,默认不实现。mRecyclerPool(缓存池)
,当cacheView满了后或者adapter被更换,将cacheView中移出的ViewHolder放到Pool中,放之前会把ViewHolder数据清除掉,所以复用时需要重新bindView。
2)四级缓存按照顺序需要依次读取。所以完整缓存流程是:
- 保存缓存流程:
- 插入或是删除
itemView
时,先把屏幕内的ViewHolder保存至AttachedScrap
中 - 滑动屏幕的时候,先消失的itemview会保存到
CacheView
,CacheView大小默认是2,超过数量的话按照先入先出原则,移出头部的itemview保存到RecyclerPool缓存池
(如果有自定义缓存就会保存到自定义缓存里),RecyclerPool缓存池会按照itemview的itemtype
进行保存,每个itemType缓存个数为5个,超过就会被回收。
- 获取缓存流程:
- AttachedScrap中获取,通过pos匹配holder——>获取失败,从
CacheView
中获取,也是通过pos获取holder缓存
——>获取失败,从自定义缓存
中获取缓存——>获取失败,从mRecyclerPool
中获取
——>获取失败,重新创建viewholder
——createViewHolder并bindview。
3)了解了缓存结构和缓存流程,我们再来看看具体的问题
滑动10个,再滑回去,会有几个执行onBindView?
- 由之前的缓存结构可知,需要重新执行
onBindView
的只有一种缓存区,就是缓存池mRecyclerPool
。
所以我们假设从加载RecyclView
开始盘的话(页面假设可以容纳7条数据):
- 首先,7条数据会依次调用
onCreateViewHolder
和onBindViewHolder
。 - 往下滑一条(position=7),那么会把position=0的数据放到
mCacheViews
中。此时mCacheViews
缓存区数量为1,mRecyclerPool
数量为0。然后新出现的position=7的数据通过postion在mCacheViews
中找不到对应的ViewHolder
,通过itemtype
也在mRecyclerPool
中找不到对应的数据,所以会调用onCreateViewHolder
和onBindViewHolder
方法。 - 再往下滑一条数据(position=8),如上。
- 再往下滑一条数据(position=9),position=2的数据会放到
mCacheViews
中,但是由于mCacheViews
缓存区默认容量为2,所以position=0的数据会被清空数据然后放到mRecyclerPool
缓存池中。而新出现的position=9数据由于在mRecyclerPool
中还是找不到相应type的ViewHolder,所以还是会走onCreateViewHolder
和onBindViewHolder
方法。所以此时mCacheViews
缓存区数量为2,mRecyclerPool
数量为1。 - 再往下滑一条数据(position=10),这时候由于可以在
mRecyclerPool
中找到相同viewtype的ViewHolder了。所以就直接复用了,并调用onBindViewHolder
方法绑定数据。 - 后面依次类推,刚消失的两条数据会被放到
mCacheViews
中,再出现的时候是不会调用onBindViewHolder方法,而复用的第三条数据是从mRecyclerPool
中取得,就会调用onBindViewHolder
方法了。
4)所以这个问题就得出结论了(假设mCacheViews
容量为默认值2):
如果一开始滑动的是新数据,那么滑动10个,就会走10个
bindview
方法。然后滑回去,会走10-2个bindview
方法。一共18次调用。如果一开始滑动的是老数据,那么滑动10-2个,就会走8个
bindview
方法。然后滑回去,会走10-2个bindview
方法。一共16次调用。
但是但是,实际情况又有点不一样。因为Recycleview
在v25版本引入了一个新的机制,预取机制
。
预取机制
,就是在滑动过程中,会把将要展示的一个元素提前缓存到mCachedViews
中,所以滑动10个元素的时候,第11个元素也会被创建,也就多走了一次bindview
方法。但是滑回去的时候不影响,因为就算提前取了一个缓存数据,只是把bindview
方法提前了,并不影响总的绑定item数量。
所以滑动的是新数据的情况下就会多一次调用bindview
方法。
5)总结,问题怎么答呢?
- 四级缓存和流程说一下。
- 滑动10个,再滑回去,
bindview
可以是19次调用,可以是16次调用。 - 缓存的其实就是缓存item的view,在Recycleview中就是
viewholder
。 cachedView
就是mCacheViews
缓存区中的view,是不需要重新绑定数据的。
如何实现RecyclerView的局部更新,用过payload吗,notifyItemChange方法中的参数?
关于RecycleView的数据更新,主要有以下几个方法:
notifyDataSetChanged()
,刷新全部可见的item。
*notifyItemChanged(int)
,刷新指定item。notifyItemRangeChanged(int,int)
,从指定位置开始刷新指定个item。notifyItemInserted(int)、notifyItemMoved(int)、notifyItemRemoved(int)
。插入、移动一个并自动刷新。notifyItemChanged(int, Object)
,局部刷新。
可以看到,关于view的局部刷新就是notifyItemChanged(int, Object)方法,下面具体说说:
notifyItemChange
有两个构造方法:
- notifyItemChanged(int position, @Nullable Object payload)
- notifyItemChanged(int position)
其中payload
参数可以认为是你要刷新的一个标示,比如我有时候只想刷新itemView
中的textview
,有时候只想刷新imageview
?又或者我只想某一个view的文字颜色进行高亮设置?那么我就可以通过payload
参数来标示这个特殊的需求了。
具体怎么做呢?比如我调用了notifyItemChanged(14,"changeColor")
,那么在onBindViewHolder
回调方法中做下判断即可:
@Override
public void onBindViewHolder(ViewHolderholder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
// payloads为空,说明是更新整个ViewHolder
onBindViewHolder(holder, position);
} else {
// payloads不为空,这只更新需要更新的View即可。
String payload = payloads.get(0).toString();
if ("changeColor".equals(payload)) {
holder.textView.setTextColor("");
}
}
}
RecyclerView嵌套RecyclerView滑动冲突,NestScrollView嵌套RecyclerView。
1)RecyclerView
嵌套RecyclerView
的情况下,如果两者都要上下滑动,那么就会引起滑动冲突。默认情况下外层的RecycleView可滑,内层不可滑。
之前说过解决滑动冲突的办法有两种:内部拦截法和外部拦截法。
这里我提供一种内部拦截法,还有一些其他的办法大家可以自己思考下。
holder.recyclerView.setOnTouchListener { v, event ->
when(event.action){
//当按下操作的时候,就通知父view不要拦截,拿起操作就设置可以拦截,正常走父view的滑动。
MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE -> v.parent.requestDisallowInterceptTouchEvent(true)
MotionEvent.ACTION_UP -> v.parent.requestDisallowInterceptTouchEvent(false)
}
false}
2)关于ScrclerView
的滑动冲突还是同样的解决办法,就是进行事件拦截。
还有一个办法就是用Nestedscrollview
代替ScrollView
,Nestedscrollview
是官方为了解决滑动冲突问题而设计的新的View。它的定义就是支持嵌套滑动的ScrollView。
所以直接替换成Nestedscrollview
就能保证两者都能正常滑动了。但是要注意设置RecyclerView.setNestedScrollingEnabled(false)
这个方法,用来取消RecyclerView本身的滑动效果。
这是因为RecyclerView默认是setNestedScrollingEnabled(true)
,这个方法的含义是支持嵌套滚动的。也就是说当它嵌套在NestedScrollView
中时,默认会随着NestedScrollView
滚动而滚动,放弃了自己的滚动。所以给我们的感觉就是滞留、卡顿。所以我们将它设置为false就解决了卡顿问题,让他正常的滑动,不受外部影响。
拜拜
今天聊了不少,关于RecycleView重要的知识点应该都涉及到了,其中bindview
的问题下次有机会我会再详细的说一下,配合图片日志。
最后希望大家好好巩固知识,加油。
拜拜
有一起学习的小伙伴可以关注下️我的公众号——码上积木,每天剖析一个知识点,我们一起积累知识。
再也不用担心问RecycleView了——面试真题详解的更多相关文章
- 软考之信息安全工程师(包含2016-2018历年真题详解+官方指定教程+VIP视频教程)
软考-中级信息安全工程师2016-2018历年考试真题以及详细答案,同时含有信息安全工程师官方指定清华版教程.信息安全工程师高清视频教程.持续更新后续年份的资料.请点赞!!请点赞!!!绝对全部货真价实 ...
- 妈妈再也不用担心别人问我是否真正用过redis了
1. Memcache与Redis的区别 1.1. 存储方式不同 1.2. 数据支持类型 1.3. 使用底层模型不同 2. Redis支持的数据类型 3. Redis的回收策略 4. Redis小命令 ...
- python爬虫07 | 有了 BeautifulSoup ,妈妈再也不用担心我的正则表达式了
我们上次做了 你的第一个爬虫,爬取当当网 Top 500 本五星好评书籍 有些朋友觉得 利用正则表达式去提取信息 太特么麻烦了 有没有什么别的方式 更方便过滤我们想要的内容啊 emmmm 你还别说 还 ...
- 使用BeautifulSoup高效解析网页,再也不用担心睡不着觉了
BeautifulSoup是一个可以从 HTML 或 XML 文件中提取数据的 Python 库 那需要怎么使用呢? 首先我们要安装一下这个库 1.pip install beautifulsoup4 ...
- 锋利的js之妈妈再也不用担心我找错钱了
用js实现收银功能. <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <hea ...
- 【阿里云产品公测】离线归档OAS,再也不用担心备份空间了
[阿里云产品公测]离线归档OAS,再也不用担心备份空间了 作者:阿里云用户莫须有3i 1 起步 1.1 初识OAS 啥是OAS,请看官方说明: 引用: 开放归档服务(Open Archive Se ...
- 有了 tldr,妈妈再也不用担心我记不住命令了
引言 有一次我在培训时说「程序员要善于使用 Terminal 以提高开发效率」,一位程序员反驳道:「这是 21 世纪,我们为什么要用落后的命令行,而不是先进的 GUI?」 是的,在一些人眼里,这个黑黑 ...
- 妈妈再也不用担心我使用git了
妈妈再也不用担心我使用git了 Dec 29, 2014 git git由于其灵活,速度快,离线工作等特点而倍受青睐,下面一步步来总结下git的基本命令和常用操作. 安装msysgit 下载地址:ms ...
- 利用CH341A编程器刷新BIOS,恢复BIOS,妈妈再也不用担心BIOS刷坏了
前几天,修电脑主析就捣鼓刷BIOS,结果刷完黑屏开不了机,立刻意识到完了,BIOS刷错了.就从网上查资料,各种方法试了个遍,什么用处都没有.终于功夫不负有心人,找到了编码器,知道了怎么用.下面看看具体 ...
随机推荐
- 如何发布代码到maven中心仓库
deploy to sonatype 参考文章 https://blog.csdn.net/xuefu_78/article/details/52494698 https://blog.csdn.ne ...
- 排名靠前的几个JS框架发展趋势和前景
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.原文出处:https://blog.bitsrc.io/top-5-javascript-frameworks ...
- 什么PO模式?
PO模式PO是Page Object的缩写,PO模式是自动化测试项目开发实践的最佳设计模式之一.核心思想是通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化, 只需要调整页面元素封 ...
- Java学习的第六天
1.今天学习了各种运算符, 还有选择结构,循环结构 2.今天学习没有遇到困难. 3.明天学习数组和第三章的开头一部分.
- 【Azure 环境】存储在Azure上的文件,使用IE/Edge时自动打开的问题,如何变为下载而非自动打开
问题描述 存储,作为云服务最重要的一部分.当需要从云存储中下载文件时,时常面临一些格式的文件被浏览器自动打开而非下载,那如何来解决这个问题呢? 在Azure中,存储的服务有以下方式: Azure Bl ...
- pandas基础读写
一.数据库读写 --以mysql为例子 1.连通器的使用 ①连通器 from sqlalchemy import create_engine 连通器=create_engine('mysql+pymy ...
- C++ storage allocation + Dynamic memory allocation + setting limits + initializer list (1)
1. 对象的空间在括号开始就已经分配,但是构造在定义对象的时候才会实现,若跳过(譬如goto),到括号结束析构会发生错误,编译会通不过. 2.初始化 1 struct X { int i ; floa ...
- C# 中的 ref 已经被放开,或许你已经不认识了
一:背景 1. 讲故事 最近在翻 netcore 源码看,发现框架中有不少的代码都被 ref 给修饰了,我去,这还是我认识的 ref 吗?就拿 Span 来说,代码如下: public readonl ...
- Java_数组, 懒得整理了 ---------------------> 未完, 待续
待续 public class TestArray { public static void main(String[] args) { String[] s1 = {"双儿", ...
- vue踩坑
1. 双向绑定的对象 改变或新增其属性 DOM不刷新问题 var obj = { "attr1": "1", "attr2": [2] }; ...