我正在尝试新的协程,并尝试将它们合并到具有一些丑陋的 AndroidNetworking api 请求的现有项目中。
所以我当前的 api 请求正在使用这样的回调...
fun getSomethingFromBackend(callback: (response: JSONArray?, error: String?) -> Unit) {
AndroidNetworking.get(...).build().getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject) { ... }
override fun onError(error: ANError) { ... }
}
}
现在我正在尝试合并这样的协程......
fun someFunction() = runBlocking {
async { callGetSomething() }.await()
}
suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
Something().getSomethingFromBackend {something
...
it.resume(something)
}
}
正如您所看到的,我正在尝试在协程中运行 callGetSomething
,一旦到达那里,就挂起协程,直到异步 API 返回。
我的问题是,它永远不会返回。即使我在 onResponse
、onError
等中调试,它也永远不会从后端返回。
但是,如果我删除 = suspendCoroutine
它会起作用,至少它会返回,但等待不会在 corse 中起作用,因为执行将继续。
如何解决这个问题,以便 await()
实际上等待异步调用回调?
非常感谢!
最佳答案
好的,谢谢大家的帮助。 我将解释我如何发现问题以及如何解决它。
在研究了有关回调和协程的更多信息后,我决定在回调期间记录线程名称,如下所示。 Log.d("TAG", "执行线程: "+Thread.currentThread().name)
.
这让我意识到所有回调(错误和成功)实际上都在主线程上运行,而不是在我为其设置的协程上运行。
因此,我的协程中的代码在 D/TAG: 执行线程:DefaultDispatcher-worker-1
中运行,但回调在 D/TAG: 执行线程:main
上运行.
解决方案
避免
runBlocking
:这会阻塞主线程,在这种情况下,这就是回调永远不会返回的原因。启动协程时使用
Dispatchers.Main
,这样我实际上可以在 UI 中使用返回的值。使用
suspendCoroutine
及其resume()
和resumeWithException
(感谢@Sergey)
示例
fun someFunction() {
GlobalScope.launch(Dispatchers.Main) {
result = GlobalScope.async { callGetSomething() }.await()
...
}
}
suspend fun callGetSomething(): JSONObject? = suspendCoroutine {
Something().getSomethingFromBackend {something
...
it.resume(something)
}
}
关于AndroidNetworking 在 Kotlin 中的 suspendCoroutine 中永远不会返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53326917/