LaunchedEffect官方文档的定义是 在Composable的作用域内使用Coroutine。定义很简单,但是看后觉得明白也不是很明白。不明白的点在于,不使用LaunchedEffect也可以在Composable的作用域内使用Coroutine,那使用LaunchedEffect的优势是什么呢?
带着疑问,我分别写了两段代码来测试,第一段代码是不使用LaunchedEffect的情况
@SuppressLint("CoroutineCreationDuringComposition")
@Composable
fun WithOutLaunchedEffect() {
val coroutine = rememberCoroutineScope()
var count by remember { mutableStateOf(1) }
Log.d("WithOutLaunchedEffect", "count: $count")
coroutine.launch {
//这里模拟启动协程进行耗时操作
delay(100)
Log.d("WithOutLaunchedEffect", "coroutine start")
}
Button(onClick = { count++ }, modifier = Modifier.statusBarsPadding()) {
Text(text = "$count")
}
}
首次运行,logcat 会打印
count: 1
coroutine start
这是我们预期之内的情况,但是如果连续点击按钮,此时logcat打印的日志就变的不对劲了
count: 2
coroutine start
count: 3
coroutine start
count: 4
coroutine start
count: 5
coroutine start
count: 6
coroutine start
每次点击按钮 Coroutine都重新运行。在使用传统view布局的时候,我们也不会希望每次 setText()或者setColor()的时候就去请求一次接口,所以这里绝大多数情况下也不是 我们需要的结果。那么,LaunchedEffect难道就是用来隔离Composable和Coroutine的吗? 接下来使用LaunchedEffect证明一下猜想
@Composable
fun UseLaunchedEffect() {
var count by remember { mutableStateOf(1) }
Log.d("UseLaunchedEffect", "count: $count")
LaunchedEffect(key1 = "key"){
delay(100)
Log.d("UseLaunchedEffect", "coroutine start")
}
Button(onClick = { count++ }, modifier = Modifier.statusBarsPadding()) {
Text(text = "$count")
}
}
首次运行的日志依然是预期的
count: 1
coroutine start
此时在点击按钮增加count 日志就变成了
count: 2
count: 3
count: 4
count: 5
count: 6
协程的没有再次执行。果然是这样证明了上面的猜测。
这里有一点需要注意的是LaunchedEffect需要至少一个key,LaunchedEffect正是根据key是否变化来决定block代码块是否重新运行。到这里LaunchedEffect的作用也就明白了
使用LaunchedEffect的时候需要注意以下3点
- LaunchedEffect必须有至少一个key
- 进入Composable代码块的时候 LaunchedEffect 开始执行,离开的时候取消
- LaunchedEffect的key变化的时候会引起block代码块重新执行