LaunchedEffect
LaunchEffect允许我们在Composable中使用协程
@Composable fun DisposableEffect(
vararg keys: Any?,
effect: DisposableEffectScope.() -> DisposableEffectResult
): Unit
- 像
DisposableEffect
一样,当Composable
进入composition时执行block - 当Composable从树上detach时,CoroutineScope执行cancel
- 参数keys发生变化是,会执行
cancel
后再次执行effect
简而言之,就是支持执行Coroutine的DisposableEffect,会自动执行cancel,不需要手动onDispose
使用方法
使用方式如下:
@Composable
fun SplashScreen(
onTimeOut: () -> Unit
) {
LaunchedEffect(Unit) {
delay(SplashWaitTime)
onTimeOut()
}
...
}
例如上面,在首次启动时显示开屏页。参数Unit,因为不会有diff,所以实现onActive的生命周期效果,即尽在首次composition时执行一次
@Composable
fun SearchScreen() {
...
var searchQuery by remember { mutableStateOf("") }
LaunchedEffect(searchQuery) {
// execute search and receive result
}
...
}
再如上,当检索词变化时,发起检索。
让Composable支持协程的重要意义是,可以让一些简单的业务逻辑直接Composable的形式封装并实现复用,而无需额外借助ViewModel。
实现原理
@Composable
@ComposableContract(restartable = false)
fun LaunchedEffect(
subject: Any?,
block: suspend CoroutineScope.() -> Unit
) {
val applyContext = currentComposer.applyCoroutineContext
remember(subject) { LaunchedEffectImpl(applyContext, block) }
}
实现非常简单,使用remember
保存了subject参数,然后通过LaunchedEffectImpl
启动协程
internal class LaunchedEffectImpl(
parentCoroutineContext: CoroutineContext,
private val task: suspend CoroutineScope.() -> Unit
) : CompositionLifecycleObserver {
private val scope = CoroutineScope(parentCoroutineContext)
private var job: Job? = null
override fun onEnter() {
job?.cancel("Old job was still running!")
job = scope.launch(block = task)
}
override fun onLeave() {
job?.cancel()
job = null
}
}
LaunchedEffectImpl
可以提供CoroutineScope
,借助CompositionLifecycleObserver
提供的生命周期,进入屏幕时launch
启动协程,离开屏幕时cancel
取消协程。