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 链与顺序、测量与命中区域》

相关推荐
麻瓜生活睁不开眼5 小时前
Android16修改全局桌面视图边框四直角显示为弧边圆角
android·java·深度学习
AFinalStone8 小时前
Android 7系统休眠唤醒(六)唤醒全链路
android·电源管理·休眠唤醒
雨白9 小时前
深入理解 Kotlin 协程 (九):互通有无,解构 Channel 缓冲策略与底层无锁机制
android·kotlin
灯塔@kuaidao10 小时前
平台交叉编译名词解释与基础流程
android
__Witheart__11 小时前
3568 Android otg模式下adb热拔插不识别
android·adb·rockchip
明天…ling13 小时前
Upload-Labs (Pass1-Pass21) 完整通关思路与源码分析
android·网络安全·渗透测试·burpsuite·upload-labs·文件上传绕过·靶场复现
__Witheart__13 小时前
3568 Android ntp校时使用
android·rockchip
molihuan13 小时前
最新 spine 4.3 flutter 适配鸿蒙
flutter·动画·harmonyos·鸿蒙·spine
wddptwd2814 小时前
android studio 报错怎么处理 java.lang.NullPointerException
android·java·android studio
GitLqr14 小时前
StatefulWidget 里的隐形炸弹:为什么不要在 State 类中使用 context.mounted
flutter·面试·dart