Android RecyclerView 性能优化指南,从零基础到精通,收藏这篇就够了!

.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

RecyclerView 是 Android 开发中高频使用的列表控件,但其性能问题常导致卡顿(尤其在快速滑动、大数据量场景)。本文从 布局优化数据绑定滑动处理图片加载 等维度,结合示例代码提供系统优化方案。

一、基础优化:减少布局计算与对象创建

1、设置固定尺寸
  • 场景:列表项尺寸固定时,避免 onMeasure() 重复计算。
recyclerView.setHasFixedSize(true)  // 若所有项尺寸一致


2、优化布局层级
  • 避免嵌套:使用 ConstraintLayout 替代多层嵌套的 LinearLayout
<!-- 示例:单层 ConstraintLayout 实现复杂布局 -->
<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <ImageView ... app:layout_constraintLeft_toLeftOf="parent" />
    <TextView ... app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>


3、复用 ViewHolder
  • 避免 findViewById:使用 ViewBindingDataBinding
class MyViewHolder(private val binding: ItemLayoutBinding) : 
    RecyclerView.ViewHolder(binding.root) {
    fun bind(data: MyData) {
        binding.title.text = data.title
    }
}


二、数据更新优化:减少无效刷新

1、使用 DiffUtil 计算差异
  • 场景:局部更新数据,避免 notifyDataSetChanged() 全量刷新。
class MyDiffCallback(
    private val oldList: List<MyData>,
    private val newList: List<MyData>
) : DiffUtil.Callback() {
    override fun getOldListSize() = oldList.size
    override fun getNewListSize() = newList.size
    override fun areItemsTheSame(oldPos: Int, newPos: Int) = 
        oldList[oldPos].id == newList[newPos].id
    override fun areContentsTheSame(oldPos: Int, newPos: Int) = 
        oldList[oldPos] == newList[newPos]
}

// 使用示例
val diffResult = DiffUtil.calculateDiff(MyDiffCallback(oldList, newList))
adapter.submitList(newList)
diffResult.dispatchUpdatesTo(adapter)


2、分页加载
  • 实现思路:滑动到底部时加载下一页数据,避免一次性加载全部。
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        if (!recyclerView.canScrollVertically(1)) {  // 到达底部
            loadNextPage()
        }
    }
})


三、快速滑动优化:避免卡顿

1、图片加载控制
  • 滑动时暂停加载(以 Glide 为例):
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        when (newState) {
            RecyclerView.SCROLL_STATE_DRAGGING -> 
                Glide.with(context).pauseRequests()  // 停止加载
            RecyclerView.SCROLL_STATE_IDLE -> 
                Glide.with(context).resumeRequests() // 恢复加载
        }
    }
})


2、预加载机制
  • 提前加载可见项前后的数据(如 ViewPager2 的 offscreenPageLimit)。

  • calculateExtraLayoutSpace 的使用

    1. 核心功能
    • calculateExtraLayoutSpaceRecyclerView.LayoutManager 的方法,用于定义超出当前可视区域外的额外布局空间

    • 通过增大布局范围,RecyclerView 可以提前加载即将进入屏幕的条目,减少滑动时的即时渲染压力。

    1. 适用场景
    • 快速滑动:用户快速滑动列表时,预加载后续条目避免白屏。
    • 复杂布局:条目布局复杂(如图文混排、动态高度)时提升渲染效率。

    示例代码

    // 自定义 `LinearLayoutManager` 实现预加载
    class PreloadLinearLayoutManager(
        context: Context,
        orientation: Int = VERTICAL,
        reverseLayout: Boolean = false
    ) : LinearLayoutManager(context, orientation, reverseLayout) {
    
        // 定义预加载的额外空间(单位:像素)
        private val extraLayoutSpace = 800 
    
        override fun calculateExtraLayoutSpace(
            state: RecyclerView.State,
            extraLayoutSpace: IntArray
        ) {
            super.calculateExtraLayoutSpace(state, extraLayoutSpace)
            // 设置前后方向的额外布局空间
            if (orientation == VERTICAL) {
                extraLayoutSpace[0] = this.extraLayoutSpace // 上方预加载区域
                extraLayoutSpace[1] = this.extraLayoutSpace // 下方预加载区域
            } else {
                extraLayoutSpace[0] = this.extraLayoutSpace // 左侧预加载区域
                extraLayoutSpace[1] = this.extraLayoutSpace // 右侧预加载区域
            }
        }
    }
    
    //应用到 RecyclerView
    recyclerView.layoutManager = PreloadLinearLayoutManager(context)
    
    
    
3、禁用动画
  • 关闭默认动画(若无需动画):
(recyclerView.itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false


四、图片加载优化:内存与流畅性

1、使用高效图片库
  • 推荐方案:Glide 或 Coil,自动处理内存缓存与复用。
// Glide 示例:加载并优化图片
Glide.with(context)
    .load(imageUrl)
    .placeholder(R.drawable.placeholder)  // 占位图
    .error(R.drawable.error)              // 错误图
    .override(Target.SIZE_ORIGINAL)       // 控制分辨率
    .diskCacheStrategy(DiskCacheStrategy.ALL)  // 缓存策略
    .into(imageView)


2、图片压缩与裁剪
  • 按控件尺寸加载:避免加载原图浪费内存。
Glide.with(context)
    .load(imageUrl)
    .override(imageView.width, imageView.height)  // 按控件大小加载
    .into(imageView)


五、高级技巧:提升复用效率

1、共享视图池(ViewPool)
  • 场景:多个 RecyclerView 显示同类项时共享复用池。
val sharedPool = RecyclerView.RecycledViewPool()
recyclerView1.setRecycledViewPool(sharedPool)
recyclerView2.setRecycledViewPool(sharedPool)


2、类型池预加载
  • 预创建 ViewHolder:减少首次渲染时的对象创建耗时。
recyclerView.setItemViewCacheSize(20)  // 增加缓存数量


六、注意事项与建议

1、避免在 onBindViewHolder 中执行耗时操作
  • 如网络请求、复杂计算应异步处理。
2、内存泄漏预防
  • onViewRecycled 中释放资源(如取消图片加载):

    override fun onViewRecycled(holder: MyViewHolder) {
        Glide.with(context).clear(holder.binding.imageView)
    }
    
    
    
3、使用 RecyclerView.setRecyclerListener 监控回收状态
  • 试时分析 ViewHolder 复用情况。

七、总结

优化方向核心措施
布局与数据绑定简化布局层级、使用 DiffUtil 局部更新
快速滑动处理滑动时暂停图片加载、禁用非必要动画
图片加载优化Glide/Coil + 压缩缓存策略
复用效率提升共享视图池、预加载 ViewHolder

通过布局简化、数据差异更新、滑动预加载、图片加载优化 等综合手段,可显著提升 RecyclerView 的性能。关键点总结:

  • 布局层级扁平化:减少测量和布局时间。
  • DiffUtil 替代全量刷新:精准更新变化项。
  • 滑动状态感知加载:平衡流畅度与用户体验。
  • 合理使用缓存:内存与磁盘缓存结合,减少重复请求。

题外话

黑客&网络安全如何学习

今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。

1.学习路线图

在这里插入图片描述

攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。

2.视频教程
网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我们和网安大厂360共同研发的网安视频教程,之前都是内部资源,专业方面绝对可以秒杀国内99%的机构和个人教学!全网独一份,你不可能在网上找到这么专业的教程。

内容涵盖了入门必备的操作系统、计算机网络和编程语言等初级知识,而且包含了中级的各种渗透技术,并且还有后期的CTF对抗、区块链安全等高阶技术。总共200多节视频,200多G的资源,不用担心学不全。
在这里插入图片描述
因篇幅有限,仅展示部分资料,需要见下图即可前往获取
在这里插入图片描述

🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源

3.技术文档和电子书
技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。

在这里插入图片描述

因篇幅有限,仅展示部分资料,需要见下图即可前往获取
在这里插入图片描述

🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源

4.工具包、面试题和源码
“工欲善其事必先利其器”我为大家总结出了最受欢迎的几十款款黑客工具。涉及范围主要集中在 信息收集、Android黑客工具、自动化工具、网络钓鱼等,感兴趣的同学不容错过。

还有我视频里讲的案例源码和对应的工具包,需要的话见下图即可前往获取
在这里插入图片描述

🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源

最后就是我这几年整理的网安方面的面试题,如果你是要找网安方面的工作,它们绝对能帮你大忙。

这些题目都是大家在面试深信服、奇安信、腾讯或者其它大厂面试时经常遇到的,如果大家有好的题目或者好的见解欢迎分享。

参考解析:深信服官网、奇安信官网、Freebuf、csdn等

内容特点:条理清晰,含图像化表示更加易懂。

内容概要:包括 内网、操作系统、协议、渗透测试、安服、漏洞、注入、XSS、CSRF、SSRF、文件上传、文件下载、文件包含、XXE、逻辑漏洞、工具、SQLmap、NMAP、BP、MSF…

在这里插入图片描述

因篇幅有限,仅展示部分资料,需要见下图即可前往获取
在这里插入图片描述

🐵这些东西我都可以免费分享给大家,需要的可以点这里自取👉:网安入门到进阶资源
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网安导师小李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值