Compose Runtime
Compose 底层 · androidx.compose.runtime
remember、key 与重组身份1.13.0-alpha01
remember 的边界、调用位置身份、重组范围与稳定性优化。
最后更新 2026-08-01
remember 的边界
val controller = remember(userId) {
ProfileController(userId)
}- 值存到当前 Composition 的调用位置(组合槽位)。
- 无 key:只在首次进入该位置计算;key 改变时重新计算。
- 跨重组保留;离开 Composition 后被遗忘;不保证进程死亡恢复。
| 需求 | 用什么 |
|---|---|
| 跨重组保留 | remember |
| 配置变更/进程恢复 | rememberSaveable(Bundle) |
| 业务状态恢复 | ViewModel + SavedStateHandle |
调用位置就是默认身份
同一个 Composable 在不同位置调用 = 不同的 remember 槽位:
// 两个独立的 remember,互不影响
if (showA) { Counter() } // 槽位 1
if (showB) { Counter() } // 槽位 2动态列表的坑:条件/循环里节点增删或重排,槽位会错位,状态串到别的项:
// ❌ 无 key:列表重排后每个项的 remember 跟着槽位走,状态错乱
messages.forEach { MessageRow(it) }
// ✅ 显式 key:状态绑定业务身份
messages.forEach { message ->
key(message.id) {
MessageRow(message)
}
}Foundation 的 Lazy 列表用 items(key = { it.id }),优先用内置 key 参数。
重组范围:不是重画整个 Activity
状态变化 → 读取该状态的组合范围失效 → 只重执行这些范围 → 生成新槽位树 → UI 层才测量/布局/绘制副作用必须进 LaunchedEffect/DisposableEffect:
// ❌ 直接写函数体:每次重组都发请求
@Composable
fun ProfileScreen(id: String) {
viewModel.load(id) // 重组就会重复调用!
}
// ✅ LaunchedEffect:按 key 触发一次
@Composable
fun ProfileScreen(id: String) {
LaunchedEffect(id) { viewModel.load(id) }
}稳定性与跳过重组
Compose 编译器会标记参数稳定(@Stable)的 Composable——重组时参数相等就跳过整个调用:
// 稳定参数:key 相同 → 跳过重组
@Composable
fun UserRow(user: User, onClick: () -> Unit)
// ❌ 不稳定:lambda 每次创建新实例 → 无法跳过
UserRow(user, onClick = { open(user.id) })
// ✅ 提升 lambda:同一实例 → 可跳过
val onUserClick = remember { { id: Long -> open(id) } }
UserRow(user, onUserClick)原则:
- 参数用不可变类型 +
@Immutable/@Stable标注。 - 回调 lambda 用
remember或提升到外部避免重建。 - 不要靠”每个重组都新建对象”假装稳定。
常见陷阱
- 副作用写进函数体:重组重复执行。
- 无 key 的动态列表:增删重排后状态错位。
- 大对象塞 remember 无 key:参数变化时意外重建。
- 认为重组=重绘:重组只重建组合树,绘制由 UI 层决定。
复制即用
@Composable
fun MessageList(messages: List<Message>, onOpen: (Long) -> Unit) {
val onOpenStable = remember { onOpen }
LazyColumn {
items(messages, key = { it.id }) { message ->
MessageRow(message, onOpenStable)
}
}
}要点
remember跨重组保留,rememberSaveable管恢复;业务状态在 ViewModel。- 调用位置是默认身份;动态列表必须用 key 绑定业务身份。
- 副作用进 LaunchedEffect;重组只重建组合树。
- 稳定参数让 Compose 跳过重组;lambda 记得 remember/提升。