窝牛号

「recycler」recyclerview缓存机制

今天窝牛号就给我们广大朋友来聊聊recycler,以下关于recyclerview缓存机制的观点希望能帮助到您找到想要的百科。

本文匹配到多条相关结果,欢迎阅读!1、recycleview一行多个时,会全部缓存吗2、Recyclerview多种场景下的优化3、RecycleView缓存4、RecyclerView的复用缓存机制recycleview一行多个时,会全部缓存吗

优质回答会。

首先说下RecycleView的缓存结构,Recycleview有四级缓存,分别是mAttachedscrap(屏幕内),mCacheviews(屏幕外),mViewcacheextension(自定义缓存),mRecyclerpool(缓存池)mAttachedscrap(屏幕内)用于屏幕内itemview快速重用,不需要重新createview和bindview,mCacheviews(屏幕外)保存最近移出屏幕的Viewholder,包含数据和position信息,复用时必须是相同位置的Viewholder才能复用,应用场景在那些需要来回滑动的列表中,当往回滑动时,能直接复用Viewholder数据,不需要重新bindview。mViewcacheextension(自定义缓存),不直接使用,需要用户自定义实现,默认不实现。mRecyclerpool(缓存池),当cacheview满了后或者adapter被更换,将cacheview中移出的Viewholder放到Pool中,放之前会把Viewholder数据清除掉,所以复用时需要重新bindview。当recycleview一行多个时,recycleview的四级缓存机制支持全部缓存。

Recyclerview的缓存机制还是非常值得到家参考的,先来说一下Recyclerview关于缓存的方法,关于Recyclerview的缓存数据有两个级别,一个是detach,另一个就是remove,关于detach就是在Recyclerview滑动或者layout时为了记录屏幕内条目信息而设定的,他主要的缓存的数据就是getchildcount列表所持有的数据,至于remove就是为了缓存我们从数据列表所删除的数据,根据这个信息我们可从代码来分析。

Recyclerview多种场景下的优化

优质回答因为APP设计的原因,Recyclerview是我在Android中最常用的组件,我们公司的APP几乎每一个页面都会包含至少一个Recyclerview,本篇文章主要介绍一些我个人在工作中总结、收集的recyclerview优化经验。

1.不要在onBindViewHolder中设置点击事件和耗时操作

Recyclerview的onBindViewHoler主要负责将数据与holder绑定,它在列表滑动时会不停的被调用。如果在onBindViewHolder中设定监听操作,会导致已经的绑定点击事件的view,被重复绑定监听操作。

点击事件的监听可以在onCreateViewHolder中设定。一些会创建新对象的操作,也需要根据实际情况考虑从onBindViewHolder中迁移到onCreateViewHolder。

注意: onBindViewHolder运行在UI线程中,如果进行了耗时操作,会导致页面卡顿。并且onBindViewHolder中只应该进行数据的绑定,而不应该进行数据的处理和计算等操作。

2.Recyclerview嵌套Recyclerview的优化

Recyclerview嵌套Recyclerview最经典的运用就是,一个纵向滑动的列表内部的每个item是一个可以横向滑动的Recyclerview,比如说GooglePlay。

这种情况可以使用LinearLayoutManager.setInitialPrefetchItemCount()设定

横向列表初次显示时可见item的个数。如果横向滑动的View中数据量很少,并且不需要横向刷新时,也可以考虑使用HorizontalScrollView实现。

关于这个API的官方文档翻译如下:

如果将此值设置为大于此视图中可见的视图数可能会导致不必要的绑定工作,并且会增加创建和活动使用的视图数。

3.多个RecycerView共用RecycledViewPool

在大多数APP中都有这样一种场景,一个ViewPager中包含多个Fragment,而Fragment中主体是Recyclerview,并且Recyclerview中item view的布局是相同的。例如 微博等

这种情况下,Recyclerview可以设定统一的缓存池用来提高性能。

新建缓存池:

设定缓存池:

4.精确的更新数据使用DiffUtil

在Recyclerview中提供了多种数据数据刷新方式

虽然有了这些刷新方式,但是实际开发中,存在这样一种情况,新数据集与旧数据集仅有一部分数据存在差异。

例如:刷新一个联系人列表,联系人列表中部分联系人的头像有变化,但是姓名和手机号码等信息未发生变化。这种情况以往都是使用notifyDataChanged方法刷新全部数据,但是刷新全部数据的会导致整个布局重绘,Recyclerview中针对这种情况还提供了另一种粒度更小的刷新方式 DiffUti

这里不打算去讲DiffUtil的具体用法,只需要记住DiffUtil的使用场景即可: 列表中存在多个Item的数据需要刷新,但是新数据集与旧数据集存在重复的情况

5.灵活设定setHasFixedSize

在Recyclerview中使用以下方法时,会触发requestLayout()

requestLayout()会重新计算item的大小,如果item的布局文件已经将宽高设为固定大小,可以设定setHasFixedSize(true),来避免Recyclerview重新计算item的大小。

6.优化Item的布局

布局优化是个老生长谈的问题,本质上就是减少嵌套,ConstraintLayout是google推出的一个用于减少布局嵌套的新layout,但是在Recyclerview中使用ConstraintLayout会导致cpu使用率上升,暂时不推荐使用,不过ConstraintLayout 2.0版本已经进入beta测试,期待后续会有优化。

7.数据非常少时,使用ListView

不知道你有没有考虑过这样的问题,RecyclerView用已经如此强大,用得人也越来越多,为什么最新的Android系统中ListView依然没有被标注为"过时"。

RecyclerView重新设计了缓存机制,新的缓存机制更加强大,更适合处理大量数据的显示,但是这种缓存机制会占据更多的内存,当一个列表页面实际数据项非常少的时候,ListView往往比RecyclerView更合适。

RecycleView缓存

优质回答RecyclerView根据不同的状态可以分为:屏幕内缓存、屏幕外缓存、自定义缓存、缓存池。RecyclerView是通过内部类Recycler来管理缓存。

一级缓存:屏幕内缓存(mAttachedScrap)

屏幕内缓存指在屏幕中显示的ViewHolder,这些ViewHolder会缓存在mAttachedScrap、mChangedScrap中 :

mChangedScrap 表示数据已经改变的ViewHolder列表,需要重新绑定数据(调用onBindViewHolder)

mAttachedScrap 未与RecyclerView分离的ViewHolder列表

二级缓存:屏幕外缓存(mCachedViews)

用来缓存移除屏幕之外的 ViewHolder,默认情况下缓存容量是 2,可以通过 setViewCacheSize 方法来改变缓存的容量大小。如果 mCachedViews 的容量已满,则会优先移除旧 ViewHolder,把旧ViewHolder移入到缓存池RecycledViewPool 中。

三级缓存:自定义缓存(ViewCacheExtension)

给用户的自定义扩展缓存,需要用户自己管理 View 的创建和缓存,可通过Recyclerview.setViewCacheExtension()设置。

四级缓存:缓存池(RecycledViewPool )

ViewHolder 缓存池,在mCachedViews中如果缓存已满的时候(默认最大值为2个),先把mCachedViews中旧的ViewHolder 存入到RecyclerViewPool。如果RecyclerViewPool缓存池已满,就不会再缓存。从缓存池中取出的ViewHolder ,需要重新调用bindViewHolder绑定数据。

按照 ViewType 来查找 ViewHolder

每个 ViewType 默认最多缓存 5 个

可以多个 RecyclerView 共享 RecycledViewPool

RecyclerViewPool底层是使用了SparseArray来分开存储不同ViewType的ViewHolder集

列表刷新优化:

对于类似于从列表进详情关注某个用户后,回到列表客户端刷新列表关注状态数据(可能不止当前item需要改变关注状态)

本地刷新,可以通过反射修改缓存数据。

1、直接修改Adapter对应的List数据,但不执行notifyDataSetChanged()方法

2、屏内缓存找到对于ViewHolder直接更新UI

3、瓶外缓存可以通过反射找到对于ViewHolder再更改UI(关键点)

屏外缓存不会触发onBindViewHolder()方法需要手动反射修改UI

4、缓存池不需做任何操作,当滑动到对应item会回调onBindViewHolder方法,然后更改UI

列表页收到广播后直接修改数据和更新UI

屏内缓存可以直接修改

更新屏外缓存UI

更新UI

RecyclerView的复用缓存机制

优质回答在正式分析缓存复用机制时,先去缓存与复用的时机在哪里。在RecyclerView滑动时,item会显示出来。所以首先先想到在onTouchEvent()中ACTION_MOVE事件里做了什么事。

接着 又到 scrollStep(x, y, mReusableIntPair) -> mLayout.scrollVerticallyBy(dy, mRecycler, mState)

->scrollBy(dy, recycler, state)[不同的layoutManager有不同的实现,这里以LinearLayoutManager为例]-> fill(recycler, mLayoutState, state)

RecyclerView的缓存分为四级

第一级 mAttachedScrap 和 mChangedScrap:RecyclerView在获取viewHolder时,其中mAttachedScrap 存储的是当前屏幕的和滑出屏幕的ViewHolder,mChangeScrap存储的是数据被更新的ViewHolder。

第二级 mCacheViews :默认的大小为2,通常用来存储预取或者准备回收的ViewHolder。

第三级 ViewCacheExtention:自定义缓存。

第四级 RecyclerViewPool:根据viewType来缓存viewHolder,每个viewType的缓存的viewHolder的个数为5.

接着往源码下找:

layoutState.next(recycler)->getViewForPosition->tryGetViewHolderForPositionByDeadline.到这里就开始RecyclerView的复用流程了。

注释①:如果有改变的viewHolder,先从mChangedScrap去查找数据被更新的viewHolder,有两种方式,一种是position另一种是id。

注释②:先从mAttachedScrap中查找废弃的ViewHolder,接着再去消失的View中去找有没有可以使用的viewHolder,最后会从mCacheViews(第一级回收缓存) 中去搜索。

注释③:先在mAttachedScrap中查找,再去mCacheViews中去寻找。

注释④:从自定义的缓存策略中去寻找。

注释⑤:从回收池RecyclerViewPool中去找,找到了返回viewHolder并从回收池中移除。

注释⑥:前面都没找到,就调用creatViewHolder去创建viewHolder了。

回收主要经历recycleByLayoutState->recycleViewsFromEnd->recycleChildren->removeAndRecycleViewAt-> recycler.recycleView(view)->recycleViewHolderInternal

注释①:mViewCacheMax 默认为2,如果mCacheViews满了,将它缓存最旧的VH放入回收池,并移除。

注释②:如果没满,就加入到mCacheViews中。

今天的内容先分享到这里了,读完本文《「recycler」recyclerview缓存机制》之后,是否是您想找的答案呢?想要了解更多,敬请关注baike.ccv168.com,您的关注是给小编最大的鼓励。

本站所发布的文字与图片素材为非商业目的改编或整理,版权归原作者所有,如侵权或涉及违法,请联系我们删除

窝牛号 wwww.93ysy.com   沪ICP备2021036305号-1