【问题标题】:Using OkHTTPClient() inside a coroutine always throws warning "inappropriate blocking method called"在协程中使用 OkHTTPClient() 总是会抛出警告“调用了不适当的阻塞方法”
【发布时间】:2020-10-04 12:04:57
【问题描述】:

在协程中调用 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)
                            }

                        })
                    }

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

【问题讨论】:

  • 协程的主要目的是摆脱回调。 enqueue 接受回调并在后台线程中运行。这里不需要协程。
  • Sergey 提出了一个很好的观点,如果你在这里启动协程,很奇怪你只是调用 enqueue。我在下面给出的答案是基于您有其他正当理由启动协程范围的假设。

标签: android kotlin okhttp kotlin-coroutines


【解决方案1】:

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()}")
}

这是来自 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)
    }
}

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 等的代码。

【讨论】:

    猜你喜欢
    • 2020-12-20
    • 2021-02-04
    • 1970-01-01
    • 2021-03-19
    • 2020-04-28
    • 1970-01-01
    • 2020-04-22
    • 1970-01-01
    • 2020-10-27
    相关资源
    最近更新 更多