我正在试验新的协程,并尝试通过一些丑陋的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
,它会起作用,至少它会返回,但是await不会在corse上起作用,因为执行只会继续。
如何解决此问题,以便await()
实际上等待异步调用回调?
非常感谢!
答案 0 :(得分:1)
好的,谢谢大家的帮助。 我将解释如何找到问题以及如何解决该问题。
在研究了有关回调和协程的更多信息之后,我决定像这样在回调过程中记录线程名称。 Log.d("TAG", "Execution thread: "+Thread.currentThread().name)
。
这使我意识到,所有回调(错误和成功)实际上在主线程上运行,而在我为其设置的协程中否。
因此,协程中的代码在D/TAG: Execution thread: DefaultDispatcher-worker-1
中运行,而回调在D/TAG: Execution thread: main
上运行。
解决方案
避免使用runBlocking
:这将阻塞主线程,在这种情况下,这是回调永不返回的原因。
在启动协程时使用Dispatchers.Main
,因此我实际上可以在UI中使用返回的值。
使用suspendCoroutine
和resume()
的{{1}}(感谢@Sergey)
示例
resumeWithException
答案 1 :(得分:0)
尝试这样的事情:
col1 = Table([[im]])
col2 = Table(data, repeatRows=1)
tblrow1 = Table([[col1, col2]], colWidths=None)
tblrow1.setStyle(
TableStyle([
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
]))
elements.append(tblrow1)
答案 2 :(得分:0)
您的主要问题是您正在尝试使用runBlocking
,这将取消您为项目引入异步网络库和协同程序所做的所有工作。如果您确实想在等待结果时进行阻止,则只需使用阻止网络调用即可。
如果您想继续使用异步网络操作,那么就不必考虑阻塞someFunction
并直接在callGetSomething
块中使用launch
:
override fun onSomeEvent(...) {
this.launch {
val result = callGetSomething(...)
// use the result, you're on the GUI thread here
}
}
以上内容假设您的this
是Activity
,Fragment
,ViewModel
或实现CoroutineScope
的类似对象。请参阅其documentation以了解如何实现。