remember、key 与重组身份 · AndroidX 源码指南
AAndroidX 源码指南
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/提升。

相关页面