Nurseyit Tursunkulov
Nurseyit Tursunkulov

Reputation: 9370

await inside await or how to get parent scope? Kotlin

I have a fucntion:

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

But compiler show Suspension functions can be called only within coroutine body for await() which inside of forEach loop. How can I avoid this problem or how can I pass parent scope for it?

**getMyChats() receives a callback

Upvotes: 0

Views: 468

Answers (2)

Dominic Fischer
Dominic Fischer

Reputation: 1849

You have to isolate the getMyChats function like @Animesh Sahu said, but that last call to await() looks very suspicious so I'll rewrite it. I'll also assume that await is not necessarily on a 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()
    }
}

If you provide the function signatures of the functions involved I might be able give you a nicer solution. Although without looking at anything else, I can tell you that the getMyChats function needs a refactor.

Upvotes: 1

Animesh Sahu
Animesh Sahu

Reputation: 8096

According to you, the getMyChats doesn't support taking suspendable block (lambda).

So you can wrap it with a suspendCancellableCoroutine.

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

Now use your function like this:

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

Obviously just chain the calls instead of creating multiple variables if you want

If you want everything to be done in single line you can do:

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

Upvotes: 1

Related Questions