美文网首页
LaunchedEffect 和 rememberUpdated

LaunchedEffect 和 rememberUpdated

作者: zcwfeng | 来源:发表于2023-05-25 11:41 被阅读0次

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 时可能很常见。

相关文章

网友评论

      本文标题:LaunchedEffect 和 rememberUpdated

      本文链接:https://www.haomeiwen.com/subject/itbesdtx.html