.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
:使用ViewBinding
或DataBinding
。
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
的使用- 核心功能
-
calculateExtraLayoutSpace
是RecyclerView.LayoutManager
的方法,用于定义超出当前可视区域外的额外布局空间。 -
通过增大布局范围,RecyclerView 可以提前加载即将进入屏幕的条目,减少滑动时的即时渲染压力。
- 适用场景
- 快速滑动:用户快速滑动列表时,预加载后续条目避免白屏。
- 复杂布局:条目布局复杂(如图文混排、动态高度)时提升渲染效率。
示例代码:
// 自定义 `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 版权协议,转载请附上原文出处链接和本声明。