在协程中使用 OkHTTPClient() 总是会抛出警告“调用了不适当的阻塞方法”

gg-*_*-05 6 android kotlin okhttp kotlin-coroutines

在协程中调用 OkHTTP 客户端的正确方法是什么?

CoroutineScope(IO).launch {
                        val request = Request.Builder()
                            .url("${host}/dots")
                            .build()

                        val client = OkHttpClient()
                        client.newCall(request).enqueue(object: Callback{
                            override fun onFailure(call: Call, e: IOException) {
                                isConnected.postValue(false)
                            }

                            override fun onResponse(call: Call, response: Response) {
                                val loadingStr = response.body()?.string().toString()
                                loadingStrings = loadingStr
                                Log.i("My_Error",loadingStrings)
                            }

                        })
                    }
Run Code Online (Sandbox Code Playgroud)

在 onResponse 中,loadingStr 变量显示 string() 警告,说明调用了不适当的阻塞方法。请告诉我正确的方法来做同样的事情。

Yur*_*mke 10

OkHttp 提供了两种并发模式

  1. 通过执行同步阻塞
  2. 通过入队异步非阻塞

在这些大多数框架之外,您使用的大多数框架将具有在不同模式和不同框架之间转换的桥接方法。

你应该使用像https://github.com/gildor/kotlin-coroutines-okhttp这样的库来为你做这件事。这段代码需要做基本的正常路径,但也特别需要处理错误和单独取消。您在协程中的代码永远不应该直接调用 enqueue。

suspend fun main() {
    // Do call and await() for result from any suspend function
    val result = client.newCall(request).await()
    println("${result.code()}: ${result.message()}")
}
Run Code Online (Sandbox Code Playgroud)

这是来自 Coil 图像加载库的另一个示例,它作为一个框架来实现它本身而不是使用库是有意义的

https://github.com/coil-kt/coil/blob/0af5fe016971ba54518a24c709feea3a1fc075eb/coil-base/src/main/java/coil/util/Extensions.kt#L45-L51

internal suspend inline fun Call.await(): Response {
    return suspendCancellableCoroutine { continuation ->
        val callback = ContinuationCallback(this, continuation)
        enqueue(callback)
        continuation.invokeOnCancellation(callback)
    }
}
Run Code Online (Sandbox Code Playgroud)

https://github.com/coil-kt/coil/blob/a17284794764ed5d0680330bfd8bca722a36bb5e/coil-base/src/main/java/coil/util/ContinuationCallback.kt

OkHttp 不能直接实现这个至少有两个原因

  1. 它将添加一个依赖 Kotlin 协程库,并需要更多的二次发布。
  2. 这个问题不是 Kotlin 协程特有的,所以 OkHttp 会有处理 RxJava 1/2/3、Spring Reactor、KTor 等的代码。