[英]Suspend Coroutine Hangs
试图更深入地了解协程。 我有一个应该获取网络响应的suspendCancellableCoroutine
。 我可以在 Charles 中看到网络调用已发送并成功返回。 但是,我的应用程序只是挂在网络请求线上。
private suspend fun fetchVisualElementsFromServer(clubId: String): VisualElements {
return suspendCancellableCoroutine { cont ->
visualElementsService.fetchVisualElementsForClub(clubId)
.enqueue(object : Callback<ResultVisualElements> {
override fun onResponse(
call: Call<ResultVisualElements>,
response: Response<ResultVisualElements>
) {
if (response.isSuccessful) {
response.body()?.let {
if (it.result == RESULT_SUCCESS) {
saveVisualElementsResponseInSharedPreferences(it.visual_elements)
cont.resume (it.visual_elements)
} else {
cont.cancel() //edit
}
} ?: cont.cancel() //edit
} else {
cont.cancel(IOException("${response.code()}: ${response.errorBody()}"))
}
}
override fun onFailure(call: Call<ResultVisualElements>, t: Throwable) {
Timber.e(t, "visual elements fetch failed")
cont.cancel() // edit
}
})
}
}
这是它挂起的地方:
视觉元素服务.kt
fun fetchVisualElementsForClub(clubId: String): Call<ResultVisualElements> {
return dataFetcherService.getVisualElementsForClub(clubId)
}
我在这里想念什么? 我试图使fetchVisualElementsForClub()
成为暂停 function,但这只会使suspendCancellableCoroutine
抛出一个Suspension functions can only be called within coroutine body
。 但我以为他在协程体内?
任何帮助表示赞赏。 谢谢。
编辑
我在下面回复 Rene 的回答,我想补充一些东西。
你是对的,我错过了三个 cont.cancel() 电话。 我已经修改了OP。 好点。
我在suspendCancellableCoroutine
都有断点,这样任何可能的情况(成功、失败等)都会受到影响。 但该回调从未注册。
想知道fetchVisualElementsForClub()
中是否缺少将回调传递给suspendCancellableCoroutine
所需的东西。 这似乎是悬挂的地方。
您必须在回调处理中的每个分支上调用cont.resume()
或cont.cancel()
。 但是在您的示例中,至少缺少三种情况。
it.result
不是RESULT_SUCCESS
你什么都不叫。onFailure
出现问题,你什么也不叫。 只要没有调用resume
或cancel
,协程就会保持挂起状态,即挂起。
当您使用暂停关键字时,您会告诉 function 应该在协同程序中调用,例如:
suspend fun abc(){
return
}
当你想在 function 上面调用时,你必须在协程中调用它,如下所示:
GlobalScope.launch {
abc()
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.