rememberUpdatedState 用法

在Android Compose中, 如果需要在协程LaunchedEffect中读取某个状态的最新状态值,而不需要重启协程需要使用到rememberUpdatedState。

下面例子在LaunchedEffect下,对delay期间状态a的值变化进行观测。
1. 使用 rememberUpdatedState
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var a by remember { mutableStateOf(1) }
Button(onClick = { a = 2 }) {
LandingScreen(a)
}
}
}
}

@Composable
fun LandingScreen(a:Int) {
val current by rememberUpdatedState(a)
Log.i("LandingScreen","a = $a")
LaunchedEffect(Unit) {
Log.i("LandingScreen","LaunchedEffect start")
delay(3000)
Log.i("LandingScreen","LaunchedEffect current=$current")
}
Text(text = "a=$a")
}

//应用启动后,3秒内点击Button,log输出结果:
a = 1
LaunchedEffect start
a = 2
LaunchedEffect current=2

从结果中可以看到当前状态值,显示为最新的状态值2,并且不重启LaunchedEffect。

2. 如果不使用rememberUpdatedState,使用remember
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Composable
fun LandingScreen(a:Int) {
val current by remember{ mutableStateOf(a) }
Log.i("LandingScreen","a = $a")
LaunchedEffect(Unit) {
Log.i("LandingScreen","LaunchedEffect start")
delay(3000)
Log.i("LandingScreen","LaunchedEffect current=$current")
}
Text(text = "a=$a")
}

//应用启动后,3秒内点击Button,log输出结果:
a = 1
LaunchedEffect start
a = 2
LaunchedEffect current=1 //current状态对象还是之前的值没有更新

从结果中可以看到当前状态值,还是显示旧的值1,并且不重启LaunchedEffect。

3. 如果不使用rememberUpdatedState,使用key标识remember和LaunchedEffect
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Composable
fun LandingScreen(a:Int) {
val current by remember(key1 = a){ mutableStateOf(a) }
Log.i("LandingScreen","a = $a")
LaunchedEffect(key1 = a) {
Log.i("LandingScreen","LaunchedEffect start")
delay(3000)
Log.i("LandingScreen","LaunchedEffect current=$current")
}
Text(text = "a=$a")
}

//应用启动后,3秒内点击Button,log输出结果:
a = 1
LaunchedEffect start
a = 2
LaunchedEffect start
LaunchedEffect current=2

从结果中可以看到当前状态值,显示为最新的状态值2,并且重启了LaunchedEffect。使用key,当状态值变更重组时,会取消当前LaunchedEffect,重启LaunchedEffect读取变更后的状态值。

rememberUpdatedState实现

1
2
3
4
@Composable  
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
mutableStateOf(newValue)
}.apply { value = newValue }

可以看到,它只是对状态值进行重新赋值了。当状态值变更重组时,会重新调用可组合项函数,并且调用一次apply。remember保存的状态对象不会改变,但它的值更新了。因此,LaunchedEffect(Unit){}会读取到最新的值。