Jetpack Compose学习之LaunchedEffect

1,148 阅读2分钟

  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代码块重新执行