一、一句话核心
rememberUpdatedState = 把一个 “会变的值” 包成一个可观察的 State,让异步 / 回调永远拿到最新值,而不是启动时的旧值。
典型场景:
LaunchedEffect里的协程长时间运行- 定时器、轮询、录音监听、动画
- 回调里需要用到外部参数,但参数已经更新了
二、为什么需要它?(经典坑)
示例:你有一个轮询,依赖外部 amplitude: Float
@Composable
fun Wave(amplitude: Float) {
LaunchedEffect(Unit) { // key = Unit,只执行一次
while (true) {
delay(300)
// 这里永远拿到第一次进入时的 amplitude!
updateWave(amplitude)
}
}
}
- 外面
amplitude变了 - 协程里捕获的还是旧值
- 这就是 “参数过时问题”
👉 解决方案:rememberUpdatedState
三、标准用法
@Composable
fun Wave(amplitude: Float) {
// 1. 把变量包一层
val currentAmp by rememberUpdatedState(amplitude)
LaunchedEffect(Unit) {
while (true) {
delay(300)
// 2. 这里永远拿到最新值
updateWave(currentAmp)
}
}
}
四、官方设计意图
rememberUpdatedState不会触发重组- 它只是把值包在一个
State对象里 - 让长时间运行的协程 / 回调能读到最新版本
- 它和
LaunchedEffect(key)解决的是不同问题
五、核心特点(必记)
-
不会引起重组它只是 “值的容器”,本身不触发重组。
-
值永远最新外部变量变化,内部读到的就是新的。
-
专门给长生命周期回调用
- 协程循环
- 定时器
- 外部回调(如第三方 SDK 监听)
- 动画监听
-
和 key 无关你不需要把它放进
LaunchedEffect(key)。
六、最经典使用场景(全覆盖)
场景 1:LaunchedEffect 轮询 / 循环(最常用)
kotlin
场景 2:DisposableEffect 注册回调
kotlin
@Composable
fun AudioObserver(amplitude: Float) {
val currentAmp by rememberUpdatedState(amplitude)
DisposableEffect(Unit) {
val callback = object : RecordCallback {
override fun onUpdate() {
// 回调里永远拿到最新 amp
doSomething(currentAmp)
}
}
register(callback)
onDispose { unregister(callback) }
}
}
场景 3:remember + 长时间回调
kotlin
val callback = remember {
{
// 这里想拿最新值必须用 rememberUpdatedState
doSomething(currentValue)
}
}
七、和普通 remember 的区别
❌ 错误:remember (amplitude)
kotlin
val amp = remember { mutableStateOf(amplitude) }
- 不会自动更新
- 依然是旧值
✅ 正确:rememberUpdatedState (amplitude)
kotlin
val amp by rememberUpdatedState(amplitude)
- 自动同步最新值
- 无重组
八、和 LaunchedEffect (key) 的区别
- LaunchedEffect(key) :key 变 → 重启整个协程
- rememberUpdatedState:不重启协程,只是让你读到新值
怎么选?
- 任务可以中断重启 → 用
LaunchedEffect(key) - 任务不能中断(录音、轮询、长连接)→ 用
rememberUpdatedState
九、极简总结口诀
- 协程跑很久,参数会变动;
- 直接用参数,旧值坑无穷;
- 包一层 rememberUpdatedState,
- 回调永远拿到最新版。