简体   繁体   English

暂停协程挂起

[英]Suspend Coroutine Hangs

Trying to get a deeper into coroutines.试图更深入地了解协程。 I have a suspendCancellableCoroutine that is supposed to fetch a network response.我有一个应该获取网络响应的suspendCancellableCoroutine I can see in Charles that the network call is dispatched and returns successfully.我可以在 Charles 中看到网络调用已发送并成功返回。 However, my app just hangs on the network request line.但是,我的应用程序只是挂在网络请求线上。

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
                }
            })
    }
}

This where it hangs:这是它挂起的地方:

VisualElementsService.kt视觉元素服务.kt

fun fetchVisualElementsForClub(clubId: String): Call<ResultVisualElements> {
    return dataFetcherService.getVisualElementsForClub(clubId)
}

What am I missing here?我在这里想念什么? I tried to make the fetchVisualElementsForClub() a suspend function, but that just makes the suspendCancellableCoroutine throw a Suspension functions can only be called within coroutine body error.我试图使fetchVisualElementsForClub()成为暂停 function,但这只会使suspendCancellableCoroutine抛出一个Suspension functions can only be called within coroutine body But I thought that his was within a coroutine body?但我以为他在协程体内?

Any help appreciated.任何帮助表示赞赏。 Thanks.谢谢。

EDIT编辑

I response to Rene's answer below, I want to add a few things.我在下面回复 Rene 的回答,我想补充一些东西。

You are right, I am missing three cont.cancel() calls.你是对的,我错过了三个 cont.cancel() 电话。 I've modified the OP.我已经修改了OP。 Good points.好点。

I have breakpoints all over the suspendCancellableCoroutine such that any possible scenario (success, failure, etc.) will be hit.我在suspendCancellableCoroutine都有断点,这样任何可能的情况(成功、失败等)都会受到影响。 But that callback never registers.但该回调从未注册。

Wondering if there is something missing in fetchVisualElementsForClub() that is needed to pass the callback up to the suspendCancellableCoroutine .想知道fetchVisualElementsForClub()中是否缺少将回调传递给suspendCancellableCoroutine所需的东西。 That seems to be where this is hanging.这似乎是悬挂的地方。

You must call cont.resume() or cont.cancel() on every branch in your callback handling.您必须在回调处理中的每个分支上调用cont.resume()cont.cancel() But in your example at least three cases are missing.但是在您的示例中,至少缺少三种情况。

  1. If the response is successful but no body is provided, you call nothing.如果响应成功但没有提供正文,则什么都不调用。
  2. If the response is successful, the body is not null, but the it.result is not RESULT_SUCCESS you call nothing.如果响应成功,body 不是 null,但是it.result不是RESULT_SUCCESS你什么都不叫。
  3. If something goes wrong in onFailure , you call nothing.如果onFailure出现问题,你什么也不叫。

As long as neither resume or cancel is invoked, the coroutine will stay suspended, means hangs.只要没有调用resumecancel ,协程就会保持挂起状态,即挂起。

when you use suspend keyword your are telling that function shoud be called inside a coroutine bode, for example:当您使用暂停关键字时,您会告诉 function 应该在协同程序中调用,例如:

suspend fun abc(){
   return
}

when you want to call above function you have to call it inside coroutines such as below:当你想在 function 上面调用时,你必须在协程中调用它,如下所示:

GlobalScope.launch {
  abc()
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM