Compose 中的附带效应是指发生在可组合函数作用域之外的应用状态的变化。例如,当用户点按一个按钮时打开一个新屏幕,或者在应用未连接到互联网时显示一条消息。
Compose 中的附带效应是指发生在可组合函数作用域之外的应用状态的变化。将状态更改为显示/隐藏着陆屏幕的操作将发生在 onTimeout
回调中,由于在调用 onTimeout
之前我们需要先使用协程加载内容,因此状态变化必须发生在协程的上下文中!
如需从可组合项内安全地调用挂起函数,请使用 LaunchedEffect
API,该 API 会在 Compose 中触发协程作用域限定的附带效应。
当 LaunchedEffect
进入组合时,它会启动一个协程,并将代码块作为参数传递。如果 LaunchedEffect
退出组合,协程将取消。
虽然接下来的代码不正确,但让我们看看如何使用此 API,并探讨为什么下面的代码是错误的。我们将在此步骤的后面调用 LandingScreen
可组合项。
// home/LandingScreen.kt file
import androidx.compose.runtime.LaunchedEffect
import kotlinx.coroutines.delay
@Composable
fun LandingScreen(onTimeout: () -> Unit, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
// Start a side effect to load things in the background
// and call onTimeout() when finished.
// Passing onTimeout as a parameter to LaunchedEffect
// is wrong! Don't do this. We'll improve this code in a sec.
LaunchedEffect(onTimeout) {
delay(SplashWaitTime) // Simulates loading things
onTimeout()
}
Image(painterResource(id = R.drawable.ic_crane_drawer), contentDescription = null)
}
}
某些附带效应 API(如 LaunchedEffect)会将可变数量的键作为参数,用于在其中一个键发生更改时重新开始效应。您发现错误了吗?我们不希望在此可组合函数的调用方传递不同的 onTimeout lambda 值时重启 LaunchedEffect。这会让 delay 再次启动,使得我们无法满足相关要求。
如果 onTimeout
在附带效应正在进行时发生变化,效应结束时不一定会调用最后一个 onTimeout
。如需保证调用最后一个 onTimeout
,请使用 rememberUpdatedState
API 记住 onTimeout
。此 API 会捕获并更新最新值:
// home/LandingScreen.kt file
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberUpdatedState
import kotlinx.coroutines.delay
@Composable
fun LandingScreen(onTimeout: () -> Unit, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
// This will always refer to the latest onTimeout function that
// LandingScreen was recomposed with
val currentOnTimeout by rememberUpdatedState(onTimeout)
// Create an effect that matches the lifecycle of LandingScreen.
// If LandingScreen recomposes or onTimeout changes,
// the delay shouldn't start again.
LaunchedEffect(Unit) {
delay(SplashWaitTime)
currentOnTimeout()
}
Image(painterResource(id = R.drawable.ic_crane_drawer), contentDescription = null)
}
}
当长期存在的 lambda 或对象表达式引用在组合期间计算的参数或值时,您应使用 rememberUpdatedState,这在使用 LaunchedEffect 时可能很常见。
网友评论