【Android】RecyclerView的经常用到的属性解析与性能优化

这篇具有很好参考价值的文章主要介绍了【Android】RecyclerView的经常用到的属性解析与性能优化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

RecyclerView

- 预加载 (加快 recyclerview 的第一屏的加载速度)

我们可以把创建对象从 oncreateviewholder 中提前到外面,用集合进行存储,用
的时候直接从集合中取

- setHasFixedSize (避免 requestLayout 浪费)

如果item的高度固定的话可以设置setHasFixedSize(true),这样RecyclerView在onMeasure阶段可以直接计算出高度,不需要多次计算子ItemView的高度。

setHasFixedSize(true)时如果是通过Adapter的增删改插方法去刷新RecyclerView,那么将不需要requestLayout()。如果是通过notifyDataSetChanged()刷新界面,还是会重新调用requestLayout()

https://www.jianshu.com/p/79c9c70f6502

recyclerView.setHasFixedSize方法什么时候设置为true 什么时候设置为false呢?

setHasFixedSize 为 true,是为了更改 adapter的内容不会改变 它的View的高度和宽度,那么就可以设置为 true来避免不必要的 requestLayout

简单的说:
(1)如果我们使用固定的宽度/高度:

<android.support.v7.widget.RecyclerView
    android:id="@+id/my_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
可以用setHasFixedSize(true)

(2)如果我们不使用固定的宽度/高度:

<android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

应该使用setHasFixedSize(false),因为宽度或高度可以改变我们的大小。

总之,如果高度固定,可以设置 setHasFixedSize(true)来避免 requestLayout 浪费
资源,否则每次更新数据都会重新测量高度当, 布局文件高度或宽度设置为固定值或者 match_parent时 ,可以设置 setHasFixedSize =true

- setItemViewCacheSize (加大RecyclerView缓存)

加大RecyclerView缓存, 比如cacheview大小默认为2,可以设置大点,用空间来换取时间,提高流畅度
RecyclerView可以设置自己所需要的ViewHolder缓存数量,默认大小是2。如果对于可能来回滑动的RecyclerView,把CacheViews的缓存数量设置大一些,可以省去bindView的时间,加快布局显示。

此方法是拿空间换时间,要充分考虑应用内存问题,根据应用实际使用情况设置大小

- setRecycledViewPool (共用回收池)

对于一个页面中的多个RecyclerView,如果使用同一个Adapter,可以使用setRecycledViewPool(pool),共用回收池

避免来每一个RecyclerView都创建一个回收池,特别是RecyclerView嵌套RecyclerView时候,内部的RecyclerView必定使用的都是同一个Adapter,这个时候就很有必要使用回收池了

- recycledViewPool.setMaxRecycledViews (增加RecycledViewPool缓存数量)

每个类型默认缓存5个

此方法是拿空间换时间,要充分考虑应用内存问题,根据应用实际使用情况设置大小

- setSupportsChangeAnimations (简化rv的内部逻辑)

对于RecyclerView,如果不需要动画,就把item动画取消

默认在开启item动画的情况下会使rv额外处理很多的逻辑判断,notify的增删改操作都会对应相应的item动画效果,所以如果你的应用不需要这些动画效果的话可以直接关闭掉,这样可以在处理增删改操作时大大简化rv的内部逻辑处理。可以通过 ((SimpleItemAnimator) rv.getItemAnimator()).setSupportsChangeAnimations(false); 把默认动画关闭


Adapter

- swapAdapter, setAdapter (两个数据源大部分相似替换Adapter)

swapAdapter, setAdapter不同点:

setadapter: 会直接清空rv上的所有缓存
swapadapter: 会将rv上的holder保存到pool中

google提供swapadapter方法考虑到的一个应用场景应该是两个数据源有很大的相似部分的情况下,直接使用setadapter重置的话会导致原本可以被复用的holder全部被清空,而使用swapadapter来代替setadapter可以充分利用rv的缓存机制,可以说是一种更为明智的选择

- 优化解耦 RecyclerView.Adapter (降低增删改ItemType成本)

我们在使用 RecyclerView 的时候,总会遇到多项 ItemType 的场景。随着业务复杂度的增加,ItemType 会越变越多,导致代码量越来越多,最终发展为 “上帝类”,需要设计出一种模式,使得增删改一种 ItemType 时的成本降到最低

https://puke3615.github.io/2018/08/26/Android-RecyclerView-Architecture-Design/

https://www.jianshu.com/p/1297d2e4d27a


LayoutManager

- setInitialItemPrefetchCount (Prefetch预取)

25.1.0 (>=21)及以上使用 Prefetch 功能,也就是预取功能,嵌套时且使用
的是 LinearLayoutManager,子 RecyclerView 可通过 setInitialPrefatchItemCount 设
置预取个数

如果你使用的是RecyclerView默认的布局管理器,你自动的就得到了这些优化。但是如果你使用嵌套的RecyclerView,或者你自己写LayoutManager,则需要自己实现Prefetch,重写collectAdjacentPrefetchPositions
https://juejin.im/entry/58a3f4f62f301e0069908d8f

https://blog.csdn.net/crazy_everyday_xrp/article/details/70344638

- getExtraLayoutSpace (为LayoutManager设置更多的预留空间)

在RecyclerView的元素比较高,一屏只能显示一个元素的时候,第一次滑动到第二个元素会卡顿。

RecyclerView (以及其他基于adapter的view,比如ListView、GridView等)使用了缓存机制重用子 view(即系统只将屏幕可见范围之内的元素保存在内存中,在滚动的时候不断的重用这些内存中已经存在的view,而不是新建view)。

这个机制会导致一个问题,启动应用之后,在屏幕可见范围内,如果只有一张卡片可见,当滚动的时 候,RecyclerView找不到可以重用的view了,它将创建一个新的,因此在滑动到第二个feed的时候就会有一定的延时,但是第二个feed之 后的滚动是流畅的,因为这个时候RecyclerView已经有能重用的view了。

如何解决这个问题呢,其实只需重写getExtraLayoutSpace()方法。根据官方文档的描述 getExtraLayoutSpace将返回LayoutManager应该预留的额外空间(显示范围之外,应该额外缓存的空间)。

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this) {
    @Override
    protected int getExtraLayoutSpace(RecyclerView.State state) {
        return 300;
    }
};

ViewHolder

- 减少布局嵌套 (减少onCreateViewHolder时间)

减少item的过度绘制, 减少布局层级,尽量少的布局嵌套,尽量少的控件

- onBindViewHolder

不要在onBindViewHolder中设置点击事件
onBindViewHolder中设置点击事件会导致快速滑动时重复创建很多对象,可以采取复用OnClickListener对象,然后在onBindViewHolder()方法中通过setTag(position) 和getTag() 的方式,来传递点击事件的position给listener。

public class TestAdapter extends RecyclerView.Adapter implements View.OnClickListener{
   ...
   @Override
   public void onBindViewHolder(final Holder holder, final int position) {
       holder.itemView.setOnClickListener(this);
       holder.itemView.setTag(position);
       ...
   }
   @Override
   public void onClick(View v) {
       int position = (Integer) v.getTag();
       Log.d("onClick", "testBtn" + String.valueOf(position));
   }
}

在ViewHolder中设置方案:https://blog.csdn.net/qq_24956515/article/details/80985773

减少耗时操作

bindViewHolder 方法是在 UI 线程进行的,此方法不能进行耗时操作,不然将会影响滑动流畅性。比如进行日期的格式化

减少调用次数

可以用一下一些方法,替代notifyDataSetChanged,达到局部刷新的目的. notifyDataSetChanged会触发所有item的detached回调再触发onAttached回调

notifyItemChanged(int position)
notifyItemInserted(int position)
notifyItemRemoved(int position)
notifyItemMoved(int fromPosition, int toPosition) 
notifyItemRangeChanged(int positionStart, int itemCount)
notifyItemRangeInserted(int positionStart, int itemCount) 
notifyItemRangeRemoved(int positionStart, int itemCount) 

如果必须用 notifyDataSetChanged(),那么最好设置 mAdapter.setHasStableIds(true),并重写getItemId()来给每个Item一个唯一的ID:

@Override
public long getItemId(int position) {
	return mDatas.get(position).hashCode();
}

这样,当我们刷新数据时,RecyclerView就能确认是否数据没有变化,ViewHolder也直接复用,减少重新布局的烦恼。但这个使用的前提是数据的id一定是唯一的。如果id不变,但数据发生变化,可能就不会刷新了

- 有大量图片时,滚动时停止加载图片,停止后再去加载图片

https://www.jianshu.com/p/a8621f917407


DiffUtil.ItemCallback

- diffutil进行局部刷新 (减少全局刷新)

对于新增或删除的时候,可以使用 diffutil 进行局部刷新,少用全局刷新
https://www.cnblogs.com/plokmju/p/7385136.html

https://zhuanlan.zhihu.com/p/26079803

参考文章: https://blog.csdn.net/hxl517116279/article/details/107058425文章来源地址https://www.toymoban.com/news/detail-842774.html

到了这里,关于【Android】RecyclerView的经常用到的属性解析与性能优化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android 性能优化——APP启动优化

            首先在《Android系统和APP启动流程》中我们介绍了 APP 的启动流程,但都是 FW 层的流程,这里我们主要分析一下在 APP 中的启动流程。要了解 APP 层的启动流程,首先要了解 APP 启动的分类。 冷启动         应用从头开始启动,即应用的首次启动。需要做大量的工

    2024年04月12日
    浏览(47)
  • Android 性能优化系列:启动优化进阶

    应用的速度优化是我们使用最频繁,也是应用最重要的优化之一,它包括启动速度优化、页面打开速度优化、功能或业务执行速度优化等等,能够直接提升应用的用户体验。 大部分人谈到速度优化,只能想到一些零碎的优化点,比如使用多线程、预加载等等,没有一个较为体

    2024年02月13日
    浏览(39)
  • Android复杂UI的性能优化实践 - PTQBookPageView 性能优化记录

    作者:彭泰强 要做性能优化,首先得知道性能怎么度量、怎么表示。因为性能是一个很抽象的词,我们必须把它量化、可视化。那么,因为是UI组件优化,我首先选用了 GPU呈现模式分析 这一工具。 在手机上的开发者模式里可以开启 GPU呈现(渲染)模式分析 这一工具,有的

    2024年02月14日
    浏览(49)
  • Android性能优化系列篇(二):启动优化

    汇总了一下众多大佬的性能优化文章,知识点,主要包含: UI优化/启动优化/崩溃优化/卡顿优化/安全性优化/弱网优化/APP深度优化等等等~ 本篇是第二篇:启动优化!  [非商业用途,如有侵权,请告知我,我会删除] 强调一下: 性能优化的开发文档跟之前的面试文档一样,想要的

    2023年04月11日
    浏览(50)
  • Android 性能优化(六):启动优化的详细流程

    书接上文,Android 性能优化(一):闪退、卡顿、耗电、APK 从用户体验角度有四个性能优化方向: 追求稳定,防止崩溃 追求流畅,防止卡顿 追求续航,防止耗损 追求精简,防止臃肿 卡顿的场景通常与用户交互体验最直接,分别为UI、启动、跳转、响应四个方面,如下图所示

    2024年04月17日
    浏览(59)
  • Android性能优化—ViewPagers + Fragment缓存优化

    大家看标题,可能会有点儿懵,什么是ViewPagers,因为在很久之前,我们使用的都是ViewPager,但是现在更多的是在用ViewPager2,因此用ViewPagers(ViewPager、ViewPager2)来代替两者,主要介绍两者的区别。 ViewPagers嵌套Fragment架构,在我们常用的App中随处可见,抖音的首页、各大电商

    2024年02月01日
    浏览(59)
  • Android中级——性能优化

    画面流畅需要帧数为60帧每秒 Android通过VSYNC信号触发对UI的绘制,其间隔时间是1000ms/60=16ms(即1000ms内显示60帧画面的单位时间) 故需在16ms之内完成绘制才可以保证画面的流畅 否则会造成丢帧,如一次绘制耗时20ms,当16ms时系统发出VSYNC信号还未绘制完,下一个帧就会被丢弃,

    2023年04月20日
    浏览(41)
  • Android系统-性能-优化概述

    目录 引言: APP优化: 网络优化: 内存优化: 卡顿优化: 先大概对Android性能优化做一个简单分类和梳理。由于性能影响因素多,比如本文分类的APP,内存,网络,卡顿都是互相影响的。卡顿应该是用户最直观可见的性能问题了。 APP优化侧重于启动,UI绘制以及资源优化这三

    2024年02月10日
    浏览(36)
  • 深入探索MySQL:成本模型解析与查询性能优化

    码到三十五 : 个人主页 在数据库管理系统中,查询优化器是一个至关重要的组件,它负责将用户提交的SQL查询转换为高效的执行计划。在MySQL中,查询优化器使用了一个称为“成本模型”的机制来评估不同执行计划的优劣,并选择其中成本最低的那个。本文将深入探讨MySQ

    2024年04月08日
    浏览(50)
  • Android UI性能优化实战 识别绘制中的性能问题

    { super.onCreate(savedInstanceState); setContentView(R.layout.activity_overdraw_01); mInflater = LayoutInflater.from(this); mListView = (ListView) findViewById(R.id.id_listview_chats); mListView.setAdapter(new ArrayAdapter(this, -1, Droid.generateDatas()) { @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder =

    2024年04月15日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包