LazyColumn 懒加载、items 与 key

源码仓库ComposeDemo(分支 main

技术目标

  1. 理解 懒组合 :可视区域附近的 item 才会进入组合,滚出可视会 disposeremember 随之清空,除非用 rememberSaveable 等策略)。
  2. 正确使用 items() / itemsIndexed()key ,避免滑动时 状态串行
  3. 知道 item lambda 的捕获范围参数稳定性(与 07 篇联动)会影响重组范围与跳过行为。

1. DSL 结构

kotlin 复制代码
LazyColumn(
    modifier = ...,
    state = rememberLazyListState(),
) {
    item { /* 单格:头图、间距块、footer */ }
    items(list, key = { it.id }, contentType = { it.type }) { row -> /* 每行 */ }
    // stickyHeader { ... } 等 API 以当前 Material/Compose 版本文档为准
}
  • item { } :不参与 itemskey 差分,适合静态头尾。
  • items / itemsIndexed :列表差分、动画、状态恢复都依赖 稳定的 key

2. key 的技术原因

key 给 Compose item 身份 :同一 key 的 item 在列表变化时被视为「同一行」的延续,从而:

  • 保留 remember 状态(如展开、输入中文字)。
  • animateItemPlacement() 等位移动画不会「飞错行」。

常见错误:

做法 后果
错误 key(如随机 uuid 每次变) 每帧重建 item,性能差且状态丢失
仅用 index 作 key 且列表 中间插入/删除 插入点之后所有行的 身份整体漂移 → checkbox 勾选跑到别的行
不同业务实体共用 key 数据覆盖、动画错乱

本仓库 LazyListSampleScreen.kt 使用 DemoRow(id = index, ...)key = { it.id } :在 静态、只追加式 的 demo 数据下等价于 index;真实业务 应使用服务端主键、稳定 uuid 等,而不是「当前列表下标」。


3. Modifier.animateItemPlacement()

启用 item 位移动画时,错误 key 常表现为「飞错行」。排障顺序建议:

  1. 关闭动画,确认数据与 key 是否正确。
  2. 打开动画,观察是否仅 插入/删除 行在动。

4. 性能相关(进阶入口)

  • contentType:不同类型 item(头图 / 文本 / 视频)帮助复用池与测量缓存策略;大列表值得加。
  • 避免在 item lambda 里捕获整个 ViewModel :把展示所需字段拆成 稳定、细粒度 参数传入子 Composable(见 07 篇)。
  • 图片 :大列表解码用 Coil / Glide Compose 等,约束尺寸,避免按原图 decode 撑爆内存。
  • verticalArrangement = spacedBy :本仓库用于 item 间距;注意与 item 内部 padding 的叠加是否符合设计。

5. 仓库路径与代码锚点

LazyListSampleScreen.kt

  • rowsremember { List(40) { ... } },避免每次重组新建列表引用。
  • items(items = rows, key = { it.id }) { row -> ... }:标准写法模板。

6. 与 Modifier.verticalScroll 的差异(排障)

场景 更适用
少量固定子项、一次全部组合可接受 Column + verticalScroll
大量行、需要视窗懒加载 LazyColumn

同向嵌套(Lazy 里再 Lazy、LazyColumn + verticalScroll)易手势冲突,见 02 篇 nestedScroll 提示。


7. 风险清单

  • 嵌套纵向 LazyColumn:需 明确高度约束nestedScroll 连接
  • rememberSaveable 保存 LazyListState分页游标 两套真相:恢复滚动位置与重新拉页逻辑要统一,避免「列表顶部但游标在第二页」。
  • 分页追加 时若整表 key 策略变化,可能触发大范围重建;追加页应保持稳定 key 空间。

8. 自检清单

  1. 列表每一项的 key 是否在插入/删除/重排后仍指向同一业务实体
  2. item 内是否有 大对象捕获非 remember 的昂贵对象创建
  3. 头尾是否误用 items 导致 多余 key 与差分 ?静态块用 item { }
  4. 图片与异步内容是否有 尺寸约束与取消(滚出视窗不再加载)?

系列推荐

《副作用 API:LaunchedEffect、DisposableEffect、SideEffect》

《Modifier 链与顺序、测量与命中区域》

相关推荐
Meteors.1 天前
安卓源码阅读——01.grade设置binding为true时,xml如何进行映射
android·xml
_李小白1 天前
【android opencv学习笔记】Day 26: 滤波算法之低通滤波与图像缩放插值
android·opencv·学习
NiceCloud喜云1 天前
Claude Code Routines 实战:三种触发器跑通云端自动化编码
android·运维·数据库·人工智能·自动化·json·飞书
woodWu1 天前
Flutter 复杂拖拽排序实战:同源排序 + 跨容器拖拽完整落地
flutter
小小小小小鹿1 天前
Vibe Coding 实战:Flutter 自定义路径布局
flutter·vibecoding
我命由我123451 天前
Bugly - Bugly 基本使用( App 质量追踪平台)
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
weiggle1 天前
第二篇:搭建你的第一个 Compose 项目——开发环境与项目结构
android·前端
阿巴斯甜1 天前
为什么 AIDL 接口客户端、服务端要写两份一模一样的?
android
程序员老刘1 天前
Dart 3.12 更新要点:乏善可陈
flutter·ai编程·dart