当前位置:首页 » 文件管理 » recyclerview缓存

recyclerview缓存

发布时间: 2023-02-26 02:05:02

A. 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更合适。

B. 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就是为了缓存我们从数据列表所删除的数据,根据这个信息我们可从代码来分析。

C. RecyclerView缓存原理及优化方向

Android新增的Recyclerview主要用于代替ListView。Recyclerview可扩展性强。

RecyclerView做性能优化要说复杂也复杂,比如说布局优化,缓存,预加载等等。

其优化的点很多,在这些看似独立的点之间,其实存在一个枢纽:Adapter。

因为所有的ViewHolder的创建和内容的绑定都需要经过Adaper的两个函数 onCreateViewHolder和onBindViewHolder 。

因此我们性能优化的本质就是要 **减少这两个函数的调用时间和调用的次数** 。

如果我们想对RecyclerView做性能优化,必须清楚的了解到我们的每一步操作背后,onCreateViewHolder和onBindViewHolder调用了多少次。

因此,了解RecyclerView的缓存机制是RecyclerView性能优化的基础。

为了简化问题,绘制原理介绍提供以下假设:

(1)类的职责介绍
LayoutManager:接管RecyclerView的Measure,Layout,Draw的过程

Recycler:缓存池

Adapter:ViewHolder的生成器和内容绑定器。

(2)绘制过程简介

RecyclerView缓存基本上是通过三个内部类管理的, Recycler 、 RecycledViewPool 和 ViewCacheExtension 。
Recycler
用于管理已经废弃或者与RecyclerView分离的ViewHolder,为了方便理解这个类,整理了下面的资料,内部类的成员变量和他们的含义:

RecycledViewPool
RecycledViewPool类是用来缓存Item用,是一个ViewHolder的缓存池,如果多个RecyclerView之间用 setRecycledViewPool(RecycledViewPool) 设置同一个RecycledViewPool,他们就可以共享Item。
其实RecycledViewPool的内部维护了一个Map,里面以不同的viewType为Key存储了各自对应的ViewHolder集合。可以通过提供的方法来修改内部缓存的Viewholder。
ViewCacheExtension
开发者可自定义的一层缓存,是虚拟类ViewCacheExtension的一个实例,开发者可实现方法getViewForPositionAndType(Recycler recycler, int position, int type)来实现自己的缓存。

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

当列表滑动出了屏幕时,ViewHolder会被缓存在 mCachedViews ,其大小由mViewCacheMax决定,默认DEFAULT_CACHE_SIZE为2,可通过Recyclerview.setItemViewCacheSize()动态设置。

可以自己实现ViewCacheExtension类实现自定义缓存,可通过Recyclerview.setViewCacheExtension()设置。

ViewHolder在首先会缓存在 mCachedViews 中,当超过了个数(比如默认为2), 就会添加到 RecycledViewPool 中。
在有限的mCachedViews中如果存不下ViewHolder时,就会把ViewHolder存入RecyclerViewPool中。
* 按照Type来查找ViewHolder
* 每个Type默认最多缓存5个

RecycledViewPool 会根据每个ViewType把ViewHolder分别存储在不同的列表中,每个ViewType最多缓存DEFAULT_MAX_SCRAP = 5 个ViewHolder,如果RecycledViewPool没有被多个RecycledView共享,对于线性布局,每个ViewType最多只有一个缓存,如果是网格有多少行就缓存多少个。

Recyclerview在获取ViewHolder时按四级缓存的顺序查找,如果没找到就创建。其中只有RecycledViewPool找到时才会调用 bindViewHolder,其它缓存不会重新bindViewHolder 。

通过了解RecyclerView的四级缓存,我们可以知道,RecyclerView最多可以缓存 N(屏幕最多可显示的item数) + 2 (屏幕外的缓存) + 5*M (M代表M个ViewType,缓存池的缓存),只有RecycledViewPool找到时才会重新调用 bindViewHolder。

RecyclerView在Recyler里面实现ViewHolder的缓存,Recycler里面的实现缓存的主要包含以下5个对象:

RecyclerView在设计的时候讲上述5个缓存对象分为了3级。
每次创建ViewHolder的时候,会按照优先级依次查询缓存创建ViewHolder 。
三级缓存分别是:

RecyclerView缓存原理,有图有真相
关于Recyclerview的缓存机制的理解

D. 谈谈RecyclerView中的缓存

Android深入理解RecyclerView的缓存机制

RecyclerView在项目中的使用已经很普遍了,可以说是项目中最高频使用的一个控件了。除了布局灵活性、丰富的动画,RecyclerView还有优秀的缓存机制,本文尝试通过源码深入了解一下RecyclerView中的缓存机制。

RecyclerView做性能优化要说复杂也复杂,比如说布局优化,缓存,预加载等等。其优化的点很多,在这些看似独立的点之间,其实存在一个枢纽:Adapter。因为所有的ViewHolder的创建和内容的绑定都需要经过Adaper的两个函数onCreateViewHolder和onBindViewHolder。

因此我们性能优化的本质就是要减少这两个函数的调用时间和调用的次数。如果我们想对RecyclerView做性能优化,必须清楚的了解到我们的每一步操作背后,onCreateViewHolder和onBindViewHolder调用了多少次。因此,了解RecyclerView的缓存机制是RecyclerView性能优化的基础。

为了理解缓存的应用场景,本文首先会简单介绍一下RecyclerView的绘制原理,然后再分析其缓存实现原理。

RecyclerView滑动时会触发onTouchEvent#onMove,回收及复用ViewHolder在这里就会开始。我们知道设置RecyclerView时需要设置LayoutManager,LayoutManager负责RecyclerView的布局,包含对ItemView的获取与复用。以LinearLayoutManager为例,当RecyclerView重新布局时会依次执行下面几个方法:

上述的整个调用链:onLayoutChildren()->fill()->layoutChunk()->next()->getViewForPosition(),getViewForPosition()即是是从RecyclerView的回收机制实现类Recycler中获取合适的View,下面主要就来从看这个Recycler#getViewForPosition()的实现。

上述逻辑用流程图表示:

RecyclerView在Recyler里面实现ViewHolder的缓存,Recycler里面的实现缓存的主要包含以下5个对象:

public final class Recycler {

final ArrayList mAttachedScrap = new ArrayList<>();

ArrayList mChangedScrap = null;

RecyclerView在设计的时候讲上述5个缓存对象分为了3级。每次创建ViewHolder的时候,会按照优先级依次查询缓存创建ViewHolder。每次讲ViewHolder缓存到Recycler缓存的时候,也会按照优先级依次缓存进去。三级缓存分别是:

使用自定义ViewCacheExtension后,view离屏后再回来不会走onBindViewHolder()方法。

holder.setIsRecyclable(false),这样的话每次都会走onCreateViewHolder()和onBindViewHolder()方法

1.提前初始化viewHolder,放到缓存池中

viewPool.putRecycledView(adapter.onCreateViewHolder(recyclerView, 1))

2.提前初始化view,在onCreateViewHolder的时候去取view

3.自定义ViewCacheExtension

4.适当的增加cacheSize

4.公用缓存池,比如多个viewPager+fragment场景使用,或者全局单利缓存池,感觉用户不大。

有2中做法有值

第一种

第二种

不会,因为prefetch(GapWorker中的一个方法)之后mViewCacheMax会变成mRequestedCacheMax + extraCache

有2种方式可以让缓存失效

第一种

recyclerView.setItemViewCacheSize(-1)

第二种

recyclerView.setItemViewCacheSize(0)

layoutManager.isItemPrefetchEnabled = false

设置不缓存后,来回滑动让view进入屏幕离开屏幕,viewHolder的item时会多次走onBindViewHolder()方法。

热点内容
安卓手机上网怎么连接电脑 发布:2025-05-20 08:28:30 浏览:548
福建公积金密码是什么 发布:2025-05-20 08:28:13 浏览:507
学习编程用什么软件好 发布:2025-05-20 08:27:28 浏览:599
我的世界电脑版服务器小游戏怎么下载 发布:2025-05-20 08:17:12 浏览:533
离线语音识别android 发布:2025-05-20 08:11:37 浏览:153
小鸟云如何去看客户服务器密码 发布:2025-05-20 07:58:51 浏览:898
怎么更改app的密码 发布:2025-05-20 07:54:32 浏览:784
汽车配置物品怎么处理 发布:2025-05-20 07:47:23 浏览:225
怎么修改华为wifi密码 发布:2025-05-20 07:45:12 浏览:41
php函数递归 发布:2025-05-20 07:39:36 浏览:781