【发布时间】:2019-10-13 03:19:24
【问题描述】:
尝试更深入地了解协程。我有一个应该获取网络响应的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
}
})
}
}
它挂在哪里:
VisualElementsService.kt
fun fetchVisualElementsForClub(clubId: String): Call<ResultVisualElements> {
return dataFetcherService.getVisualElementsForClub(clubId)
}
我在这里缺少什么?我试图使fetchVisualElementsForClub() 成为挂起函数,但这只会使suspendCancellableCoroutine 引发Suspension functions can only be called within coroutine body 错误。但我以为他在协程体内?
任何帮助表示赞赏。谢谢。
编辑
我在下面回复Rene的回答,我想补充几点。
你是对的,我错过了三个 cont.cancel() 调用。我已经修改了OP。好点。
我在suspendCancellableCoroutine 各处都有断点,这样任何可能的情况(成功、失败等)都会受到影响。但是那个回调从不注册。
想知道fetchVisualElementsForClub() 中是否缺少将回调传递给suspendCancellableCoroutine 所需的内容。这似乎是它挂的地方。
【问题讨论】:
-
你使用什么版本的 kotlinx-coroutines-core?您的代码无法编译,例如1.2.0 具有以下简历签名:
CancellableContinuation.resume(value: T, onCancellation: (cause: Throwable) -> Unit)。也许您在该库的早期版本中遇到了在更高版本中修复的错误;尝试适应并升级到这个库的最新版本。 -
1.3.0.我向你保证,我的代码编译并且应用程序运行。至少到它挂起的地步。 :-)
-
奇怪的是它为你编译,因为我可以在 Kotlin Playground 中重现编译错误:pl.kotl.in/xlX8nRuAK
标签: android kotlin kotlin-coroutines