gg-dev-05
gg-dev-05

Reputation: 407

Using OkHTTPClient() inside a coroutine always throws warning "inappropriate blocking method called"

What is the correct way to call the OkHTTP client inside a Coroutine?

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

                        })
                    }

In the onResponse the loadingStr variable shows warning for string() saying inappropriate blocking method called. Please tell me the correct way to do the same.

Upvotes: 9

Views: 12789

Answers (1)

Yuri Schimke
Yuri Schimke

Reputation: 13448

OkHttp provides two modes of concurrency

  1. Synchronous blocking via execute
  2. Asynchronous non-blocking via enqueue

Outside of these most frameworks you use will have bridge methods that convert between different modes and difference frameworks.

You should use a library like https://github.com/gildor/kotlin-coroutines-okhttp to do it for you. This code needs to do the basic normal path but also specifically needs to handle errors and separately cancellation. Your code inside coroutines should never be calling enqueue directly.

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

This is another example from the Coil image loading library which as a framework makes sense to implement this itself rather than using a library

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 can't implement this directly for at least two reasons

  1. It would add a dependency Kotlin coroutines library, and require more secondary releases.
  2. This problem isn't specific to Kotlin coroutines, so OkHttp would have code to deal with RxJava 1/2/3, Spring Reactor, KTor etc.

Upvotes: 19

Related Questions