从“货架整理”到“自动化仓库”:Android 列表与图片优化的新旧范式

224 阅读4分钟

一句话总结:

传统列表优化的本质,是在 16.6ms 内打赢一场 onBindViewHolder 的“闪电战”;而现代 Jetpack Compose 的 LazyColumn,则通过架构革新,将这场战斗的大部分流程自动化了。


第一篇章:“手动挡”的极限艺术——榨干 RecyclerView 的每一滴性能

在传统的 View 体系中,RecyclerView 是我们唯一的选择。它的性能瓶颈高度统一:onBindViewHolder 方法的执行时间。我们的所有优化,都是为了让这个方法更快,或者让它被调用的次数更少。

1. 核心战场:onBindViewHolder 耗时保卫战

目标:让它在 2-3 毫秒内完成!

  • 减轻布局负担(让“快递盒”更轻):

    • 扁平化 Item 布局: 这是最重要的优化!使用 ConstraintLayout 将 Item 的视图层级降到最低。每多一层嵌套,measure/layout 的成本都可能翻倍。
  • 高效加载图片(让“货物”秒速入盒):

    • 尺寸压缩: 使用 Glide/Coiloverride() 方法,确保加载的图片尺寸不超过 ImageView 的显示尺寸。这是图片优化中最有效的一步。
    • 格式与质量: 优先使用 WebP/AVIF 格式。
    • 缓存: 充分利用内存和磁盘缓存,避免网络请求。Glide/Coil 默认已开启。
  • 避免复杂计算: 不要在 onBindViewHolder 中执行任何耗时计算、字符串拼接或复杂的逻辑判断。这些都应在数据预处理阶段(如 ViewModel 中)完成。

2. 战略武器:减少不必要的调用

  • DiffUtil(精准更新): 当数据列表更新时,使用 DiffUtil 计算出最小变更集,实现“哪里变了刷哪里”,避免 notifyDataSetChanged() 带来的全局刷新。
  • Payloads(负载更新): DiffUtil 的进阶版。当 Item 内部只有某个元素(如一个点赞数)变化时,可以只更新那个 TextView,而不是重新绑定整个 Item View。

3. 高级战术:挖掘 RecyclerView 潜能

  • 共享缓存池 (RecycledViewPool): 如果你在 ViewPager2 中嵌套了多个 RecyclerView,让它们共享同一个 RecycledViewPool,可以奇迹般地提升切换流畅度。
  • 预取 (Prefetch): 确保 LayoutManager.setItemPrefetchEnabled(true) 开启(默认),RecyclerView 会在主线程空闲时,提前创建和绑定即将进入屏幕的 Item。

第二篇章:“自动挡”的降维打击——Jetpack Compose 的 LazyColumn

Jetpack Compose 带来了全新的范式。它不是对 RecyclerView 的优化,而是“重新发明轮子”,并让这个轮子变成了“自动驾驶”。

1. 告别样板代码:再见,AdapterViewHolder

Compose 用一个简单的 LazyColumn 替代了 RecyclerView 的整套复杂系统。

// 在 Compose 中实现一个带图片的高性能列表
LazyColumn(state = listState) {
    items(
        items = userList,
        key = { user -> user.id } // 提供稳定的 Key,Compose 自动处理 Diff
    ) { user ->
        // UserRow 就是你的列表项,一个普通的 Composable 函数
        UserRow(user)
    }
}

@Composable
fun UserRow(user: User) {
    Row {
        // Coil 的 AsyncImage,自动处理生命周期、缓存和占位符
        AsyncImage(
            model = user.avatarUrl,
            contentDescription = null,
            modifier = Modifier.size(48.dp)
        )
        Text(text = user.name)
    }
}

2. 架构性的性能优势

  • “复用”的进化: Compose 不再复用 View 对象,而是通过“智能重组”跳过未变化 Composable 的执行。它在更低的层级实现了更高效的“复用”。
  • “差分”的内建: 你只需为列表项提供一个稳定的 key,Compose 就能在数据变化时,自动实现类似 DiffUtil 的高效更新。
  • “滑动暂停”的自动化:LazyColumn 中使用 AsyncImage(Coil)或 GlideImage(Glide)时,这些库的 Compose 版本已经考虑到了列表滚动场景,能更智能地处理请求的暂停与恢复,通常无需手动干预。

三、总结:你的优化策略

场景推荐策略核心思想
维护现有的 RecyclerView 页面遵循第一篇章的“手动挡”优化法则,将 onBindViewHolder 耗时降到最低。在既有规则下做到极致
开发全新的列表页面毫不犹豫地选择 Jetpack Compose 的 LazyColumn拥抱“自动挡”,享受架构带来的红利
图片优化(通用原则)无论 View 还是 Compose“尺寸、格式、缓存” 三原则永不过时。优化数据本身是根本

最终,列表优化的演进路径,是从“如何手动把每个环节都做好”,走向“如何选择一个能自动把所有环节都做好的架构”。