这是关于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的含义是什么?

最佳答案

一般情况:使用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挂起而不是阻止
  • 10-08 03:13