【发布时间】:2021-09-29 16:38:06
【问题描述】:
我正在使用 OkHttp 发出同步 http 请求。为了避免阻塞主线程,我将阻塞的网络调用包裹在一个挂起函数和withContext(Dispatchers.IO)
suspend fun run(): String {
val client = OkHttpClient()
val request = Request.Builder()
.url("https://publicobject.com/helloworld.txt")
.build()
return withContext(Dispatchers.IO) {
val response = client.newCall(request).execute()
return@withContext "Request completed successfully"
}
}
Android Studio 给我一个警告,execute() 是一个“不适当的阻塞方法调用”。我的理解是,execute() 会在 http 请求期间阻塞,在请求期间占用 Dispatchers.IO 中的一个线程,这并不理想。为了避免这个问题,我可以使用包裹在suspendCoroutine中的异步版本的请求
suspend fun runAsync(): String = suspendCoroutine { continuation ->
val client = OkHttpClient()
val request = Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
continuation.resumeWithException(e)
}
override fun onResponse(call: Call, response: Response) {
response.use {
if (!response.isSuccessful) throw IOException("Unexpected code $response")
continuation.resume("Request completed successfully")
}
}
})
}
这避免了警告,但我不明白它在功能上与上面的同步版本有何不同。我假设 http 调用的异步版本使用线程来等待请求。这个假设正确吗?如果没有,异步函数如何等待回调返回?
【问题讨论】: