我目前正在尝试更多地利用kotlin协程。但我面临一个问题:当在这些协程中使用moshi或okhttp时,我得到一个警告:

“不恰当的阻塞方法调用”

解决这些问题的最好方法是什么?我真的不想不合适;-)


当前回答

我使用dispatchers作为启动参数:

    GlobalScope.launch(Dispatchers.IO) {
        // Do background work
        
        // Back to main thread
        launch(Dispatchers.Main) {
            Toast.makeText(context, "SUCCESS!", Toast.LENGTH_LONG)
                .show()
        }
    }

其他回答

可能会发生异常,这就是为什么会显示此警告。使用runCatching{}。它捕获从块函数执行中抛出的任何Throwable异常,并将其封装为失败。

例如:

 CoroutineScope(Dispatchers.IO).launch {
         runCatching{
               makeHttpRequest(URL(downloadLocation))
         }
}

一个解决方案是通过挂起有趣的kotlinx. corroutine . runinterruptible来包装阻塞代码。 如果没有它,当协程的任务被取消时,阻塞代码将不会中断。

它抑制了编译警告,阻塞代码将在取消时抛出InterruptedException

val job = launch {
  runInterruptible(Dispatchers.IO) {
    Thread.sleep(500) // example blocking code
  }
}

job.cancelAndJoin() // Cause will be 'java.lang.InterruptedException'

https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-interruptible.html

如何将Java阻塞函数转换为可取消的挂起函数?

此警告是关于阻塞当前线程和协程的方法不能正确挂起。这样,您就失去了协程的所有好处,并再次降级为每个线程一个任务。

每一种情况都应以不同的方式处理。对于可悬挂的http调用,您可以使用ktor http客户端。但有时没有针对您的情况的库,因此您可以编写自己的解决方案,或者忽略此警告。

编辑:withContext(Dispatchers.IO)或一些自定义调度程序可以用来解决这个问题。谢谢你的评论。

这就是如何挂起协程,在线程中运行阻塞方法,并在结果上恢复它。这也将处理异常,所以你的应用程序不会崩溃。

suspendCoroutine { continuation ->
    thread {
        try {
            doHttpRequest(URL(...)) {
                continuation.resume(it)
            }
        }
        catch (t: Throwable) {
            continuation.resumeWithException(t)
        }
    }
}

编辑:预期的方法是使用witchContext(Dispatchers.IO)。我把这个回答留在这里,以防有人发现这种方法有用。

当调用带有@Throws(IOException::class)注释的挂起函数(Kotlin 1.3.61)时,也会收到此警告。不确定这是否是有意为之。无论如何,您可以通过删除该注释或将其更改为Exception类来抑制此警告。