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

相关推荐
汪海游龙2 分钟前
本地源码还是 Maven 版本?Gradle composite build 双轨依赖的正确接法
android·ci/cd·kotlin
k3x1n16 分钟前
三星安卓系统BUG排查记录:云闪付、铁路12306、个人所得税、中国移动等App,长期闪退的根本原因分析
android·逆向
GitLqr19 分钟前
Flutter 实战:图片上传前的压缩优化,解决带宽与存储的“大户”问题
flutter·全栈·dart
网安蟹佬霸2 小时前
CTF Web方向解题全攻略:从信息收集到getshell(附实战payload与脚本)
android·前端·网络·安全·web安全·网络安全·网安
又见情义2 小时前
Android 13 Settings 设置界面选项裁剪(RK3568平台)
android
人才瘾大3 小时前
Android录屏内部音频录制完全指南:原理、限制与方案选型
android·音视频
网安蟹佬霸4 小时前
Webshell免杀与检测实战:从一句话木马到加密流量
android·安全·web安全·网络安全·黑客·网安·渗透测试·
进哥AI研习社4 小时前
AtomCode 跨端开发实战:Flutter 项目从原型到多端运行的 AI 驱动体验
人工智能·flutter
阿巴斯甜7 小时前
Android SharedMemory 详细使用
android
sun0077007 小时前
android的dns的常见错误resolv
android