开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
Compose里面的附带效应用的最多的就是LaunchedEffect。今天专门去官网把这一章节看了一下,之前别人一直把这个叫附带效应,但是一直都不太明白所谓的附带效应是什么,今天就先理解一下什么是附带效应,看看官网给出的解释:附带效应是指对应用的其余部分可见的任何更改。这句话感觉有那么的一点抽象,按照我理解的举一个例子:
var count = 0
@Composable
fun MainScreen(){
var state by remember {
mutableStateOf(false)
}
count++
Button(onClick = { state = !state }) {
Text(text = "click")
}
if(state){
Text(text = "my Count:$count")
}
}
上面的方法中全局变量count在什么时候会增加呢?第一是函数调用的地方,第二就是重组的时候,而重组时所触发的这个值的改变就属于附带效应。官网也有这么一句话:切勿依赖于执行可组合函数所产生的附带效应,因为可能会跳过函数的重组。所以靠组合函数的这种附带效应结果是不可预知的,是需要杜绝的。那如果我们需要在Composable函数中使用附带效应怎么办?另外一方面,如果我们确实要在composable中做一些耗时的操作该怎么办?例如动画等,这个时候我们就可以使用官方给我们提供的方法,不管是LaunchedEffect,DisposableEffect 还是 SideEffect都是提供附带效应的方式,只是在使用上和生命周期上不同,可以应该不同的附带效应场景。下面我们一个一个举例子来看:
- LaunchedEffect
LaunchedEffect可以在某一个可组项中运行挂起函数。退出组合时协程取消。看一下它的定义:
fun LaunchedEffect(
key1: Any?,
block: suspend CoroutineScope.() -> Unit
) {
val applyContext = currentComposer.applyCoroutineContext
remember(key1) { LaunchedEffectImpl(applyContext, block) }
}
block就是要执行的挂起函数,那key1是什么呢,从定义看key1可以为任何值,这里分几种:
- state变量,如果key1为state变量,那么当state的值改变时LaunchedEffect将取消当前协程并重新启动新的协程执行挂起函数。
- key1为Unit或者true时,这个时候LaunchedEffect和当前重组函数保持一致的生命周期。
- 普通变量:普通变量值的变化也不会引起当前协程的取消。 LaunchedEffect是只能在可组合函数内使用,如果想在可组合函数外使用,并且生命周期还需要和可组合函数相同,那么这个时候可以使用rememberCoroutineScope,看下面一个简单的例子
val scope = rememberCoroutineScope()
Button(onClick = { scope.launch { Log.i("test","I will do some important job here") } }) {
}
在onClick中要执行耗时的操作,这个时候就可以使用rememberCoroutineScope。
- DisposableEffect LaunchedEffect只是在state发生改变的时候才会取消协程启动新的协程,那么如果需要每次重组的时候都需要做清理工作那该怎么办呢?这个时候就可以使用DisposableEffect。看下面的例子:
var count by remember {
mutableStateOf(0)
}
DisposableEffect(count){
if(count < 100){
count++
}
onDispose {
count =0
}
}
使用DisposableEffect必须需要实现onDispose,即在退出的时候做清理工作,需要注意的是DisposableEffect不能执行挂起函数。如果需要执行挂起函数那就使用上面的:rememberCoroutineScope。
- SideEffect
对于SideEffect官网给的作用是:将 Compose 状态发布为非 Compose 代码。这个应该怎么理解呢?我们来看一个例子:
@Composable
fun userName(brand:String):Car{
val car = remember {
Car(Color.BLUE,"BMW")
}
SideEffect {
car.brand = brand
}
return car
}
car是一个remember对象,我们在这里把它进行了返回,传给非composable函数使用。SideEffect会在每次重组的时候都发生改变,所以共享了同一个值。
上面都是列举了一些简单的例子,其实在实际使用中还没有遇到过太多的问题,所以也没有经典的活着突出的例子,如果你有,可以分享出来哦~~