Kotlin协程:在Kotlin global.launch中运行

时间:2019-05-16 08:04:31

标签: kotlin kotlin-coroutines

这是关于runBlocking的错误用法吗? 正如“ runBlocking”文档所说的This function should not be used from coroutine

此代码段来自camerakit-android库。

    fun start(facing: CameraFacing) {
        GlobalScope.launch(cameraDispatcher) {
            runBlocking {
                lifecycleState = LifecycleState.STARTED
                cameraFacing = facing
                openCamera()
            }
        }
    }

删除runBlocking后,它无法工作。 那么runBlocking在这里是什么意思?

2 个答案:

答案 0 :(得分:1)

一般情况:使用coroutineScope代替runBlocking

作为一般规则,如果您已经在协程环境中(在暂停功能中),则始终应优先考虑暂停而不是阻塞。正如您所指出的,这就是为什么在协程中不建议使用runBlocking,因为它不必要地阻塞了当前线程。

因此,只要您感觉需要在挂起函数中使用runBlocking,就应该使用coroutineScope。这是runBlocking的暂停等效项,因为它在返回之前会等待所有子协程完成执行:

    fun start(facing: CameraFacing) {
        GlobalScope.launch(cameraDispatcher) {
            coroutineScope {
                lifecycleState = LifecycleState.STARTED
                cameraFacing = facing
                openCamera()
            }
        }
    }

您的情况:缺少结构化并发吗?

在您的特定情况下,由于您说如果没有runBlocking它就“无法工作”,我怀疑openCamera()会自己启动协程。

启动协程的最佳实践是structured concurrency。这意味着将协程作为当前协程的子级启动,而不是使用GlobalScope来启动全局协程。

如果openCamera()使用GlobalScope启动协程,除非使用runBlocking,否则您将无法等待它完成,因为即使coroutineScope提供范围,调用GlobalScope.launch时将不使用它。

请清楚一点,阻止您在此处使用coroutineScope(并迫使您使用runBlocking)的原因不是在内部 GlobalScope.launch,而是它正在调用本身使用GlobalScope.launch的函数(我怀疑openCamera()在这里这样做)。

如果您真的想做正确的事:

  • openCamera()start()声明为CoroutineScope的扩展名
  • 删除所有GlobalScope的用法,使用launch,将隐式接收器作为您现在拥有的范围
  • 使用coroutineScope而非runBlocking暂停而不是阻止

答案 1 :(得分:0)

是的,这是错误的,因为它废除了协程必须提供的一切。这是一种更加复杂和混乱的书写方式

yourJavaExecutor.submit {
    lifecycleState = LifecycleState.STARTED
    cameraFacing = facing
    openCamera()
}

换句话说,您什么也不做,只能将阻止任务提交给后台线程。