Kotlin`launch`语句仅在`runBlocking`内部编译

oxf4rvwz  于 2023-04-12  发布在  Kotlin
关注(0)|答案(1)|浏览(104)

我正在使用最新版本的Kotlin,并尝试在Android DataStore中使用协程。我不是协程Maven。我读到过你不应该使用runBlocking,因为它会挂起整个线程。
但是我完全被以下代码编译并运行良好的事实所迷惑:

runBlocking {
    launch {
        shouldBypassSplashScreen = mainViewModel.isBypassSplashScreenOptChecked()
    }
}

但是,这段代码与上面的代码相同,没有runBlocking,得到了一个编译错误,告诉我launch是未定义的:

launch {
    shouldBypassSplashScreen = mainViewModel.isBypassSplashScreenOptChecked()
}

这确实是我使用runBlocking的唯一原因,因为没有它我就无法克服编译错误。

sd2nnvve

sd2nnvve1#

launch是CoroutineScope的扩展。因此,您需要使用CoroutineScope对象调用它。
runBlocking将lambda作为其最后一个参数,并将CoroutineScope作为接收器,这就是为什么它在这种情况下工作。
你需要一些CoroutineScope来调用launch-如果你在一个Lifecycle对象中,可能是一个lifecycleScope,如果你在一个Fragment中,可能是viewLifeCycleScope,或者是视图模型的viewmodelScope

mostAppropriateScopeToUseInThisCase.launch {
    shouldBypassSplashScreen = mainViewModel.isBypassSplashScreenOptChecked()
}

编辑:
我在一个Jetpack Compose composable中。我所要做的就是等待从Android DataStore读取选项,这就是为什么我需要异步。
免责声明:我只是简单地看了一下Compose。但是...
我不认为你应该在一个组合中运行suspend函数,我的理解是你有一些在组合中使用的状态对象,并且状态由你的视图模型异步更新。
类似于:

// ViewModel
class ViewModel {
    val shouldBypassSplashScreen by mutableStateOf(false)

    init {
        viewmodelScope.launch {
            shouldBypassSplashScreen = datastore.shouldBypassSplashScreen
        }
    }
 }

然后,您的组合对象只需检查ViewModel上的shouldBypassSplashScreen属性,并在状态更改时重新组合。组合对象中不需要corouties。
我还是个新手,所以这可能不是100%正确,但也许它为您指明了正确的方向。

相关问题