ждать внутри ждать или как получить родительский охват? Kotlin - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть функция:

suspend fun getChats() {
    val chatList = mutableListOf<Chat>()
    getMyChats { chats ->
        chats.forEach {
            it.getDetail().await()
        }
    }.await()
}

Но компилятор покажет Suspension functions can be called only within coroutine body для await() который внутри forEach l oop. Как мне избежать этой проблемы или как передать родительскую область видимости для нее?

** getMyChats () получает обратный вызов

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

Вы должны изолировать функцию getMyChats, как @ Anime sh, сказал Саху, но этот последний вызов await() выглядит очень подозрительно, поэтому я перепишу его. Я также предполагаю, что await необязательно для Deferred<T>.

suspend fun getChats() {
    val chatList = mutableListOf<Chat>()

    val result = CompletableDeferred<List<Chat>>()
    getMyChats { result.complete(it) }.await()
    val chats = result.await()
    chats.forEach {
        it.getDetail().await()
    }
}

Если вы предоставите сигнатуры функций задействованных функций, я мог бы дать вам более подходящее решение. Хотя, не смотря ни на что другое, я могу сказать, что функция getMyChats нуждается в рефакторинге.

1 голос
/ 27 апреля 2020

По вашему мнению, getMyChats не поддерживает взятие приостановленного блока (лямбда).

Так что вы можете обернуть его с помощью suspendCancellableCoroutine .

suspend fun getMyChatsSuspend(): List<Chat> = suspendCancellableCoroutine { cont ->
    getMyChats { cont.resume(it) }
}

Теперь используйте вашу функцию следующим образом:

suspend fun getChats() {
    ...
    val chats = getMyChatsSuspend()
    val chatDetails = chats.map{ chat.getDetail() }
    val chatDetailsAwait = awaitAll( *chatDetails.toTypedArray() )
}

Очевидно, просто цепочка вызовов вместо создания нескольких переменных, если вы хотите

Если вы хотите, чтобы все было сделано в одну строку, вы можете сделать :

val resolvedDetails = getMyChatsSuspend().map{ chat.getDetail() }.let { awaitAll(*it.toTypedArray()) }
...