Приостановить сопрограммы висит - PullRequest
0 голосов
/ 13 октября 2019

Пытаясь глубже проникнуть в сопрограммы. У меня есть suspendCancellableCoroutine, который должен получить сетевой ответ. Я вижу в Чарльзе, что сетевой вызов отправляется и успешно возвращается. Однако мое приложение просто висит на строке сетевого запроса.

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 ошибку. Но я думал, что он был в теле сопрограммы?

Любая помощь приветствуется. Спасибо.

РЕДАКТИРОВАТЬ

Я отвечаю на ответ Рене ниже, хочу добавить несколько вещей.

Вы правы, я пропускаю три вызова cont.cancel (),Я изменил ОП. Хорошие очки.

У меня есть точки останова по всему suspendCancellableCoroutine, так что любой возможный сценарий (успех, неудача и т. Д.) Будет достигнут. Но этот обратный вызов никогда не регистрируется .

Интересно, если в fetchVisualElementsForClub() чего-то не хватает, что необходимо для передачи обратного вызова до suspendCancellableCoroutine. Кажется, вот где это висит.

Ответы [ 2 ]

2 голосов
/ 13 октября 2019

Вы должны звонить cont.resume() или cont.cancel() в каждой ветви вашей обработки обратных вызовов. Но в вашем примере по крайней мере три случая отсутствуют.

  1. Если ответ успешен, но тело не указано, вы ничего не вызываете.
  2. Если ответ успешен, телоне нуль, но it.result не является RESULT_SUCCESS, который вы не называете.
  3. Если что-то не так в onFailure, вы ничего не вызываете.

Пока ни то, ни другое resume или cancel вызывается, сопрограмма останется приостановленной, значит зависает.

0 голосов
/ 13 октября 2019

когда вы используете ключевое слово suspend, вы говорите, что функция должна вызываться внутри сопрограммы, например:

suspend fun abc(){
   return
}

, когда вы хотите вызвать функцию выше, вы должны вызывать ее внутри сопрограмм, как показано ниже:

GlobalScope.launch {
  abc()
}
...