bobby I.
bobby I.

Reputation: 113

Coroutine await() function not waiting till it's job done

I had a code that looks like below

fun main() {
    viewModelScope.launch {
        doA()
        //call api with Flow as the return type
    }
}
suspend fun doA() {
    viewModelScope.async { doB() }.await()
}
suspend fun doB() {
    //Do logic here, eventually will call line below
    viewModelScope.launch { doC() }
}
suspend fun doC() {
    //call api with Flow as the return type
}

What I want to achieve here is to make the doA() wait till it's done and after that continue to the function below it, which is the call API function. But when I try to run, the doA() not wait until everything finishes on that side. The debug quite help me and I found that when the doB() being run and reach the doC() which in the new scope, the program continues to the next line after the doA() in main().

Is there's something I missing? Why the code doesn't work like what I want? I kind a new in Coroutine to say. And yes, I run the code in the Android environment. Thanks for helping

Upvotes: 2

Views: 3200

Answers (2)

Sreeji
Sreeji

Reputation: 101

Me too Beginner. As per my LIMITED UNDERSTANDING, "async" should be used for running "parallel" jobs and wait for "future results"

For getting the jobs done "sequentially", instead "launch" and "join" should be used. Plz check Waiting for a job

Regarding the doA() finishing while doB() is running, its because in doB(), a NEW COROUTINE is launched and it immediately returns, hence the Execution continues with the Next Line in doA(). To make doA() wait, add "join" in doB() while launching the Coroutine

fun main() {
    viewModelScope.launch {
        doA()
        //call api with Flow as the return type
    }
}
suspend fun doA() {
    //viewModelScope.async { doB() }.await()

    // Replace with "launch" and "join"
    viewModelScope.launch{ doB() }.join()
}
suspend fun doB() {
    //Do logic here, eventually will call line below
    //viewModelScope.launch { doC() }

    // Add join() to make it wait 
    viewModelScope.launch { doC() }.join()
}
suspend fun doC() {
    //call api with Flow as the return type
}

But if you prefer to keep using "async", then just add "join" in doB()

suspend fun doB() {
    //Do logic here, eventually will call line below
    //viewModelScope.launch { doC() }

    // Add join() to make it wait
    viewModelScope.launch { doC() }.join()
}

Upvotes: 5

iamanbansal
iamanbansal

Reputation: 2732

For doB() and doC() you're creating new coroutine to run, so it doesn't run in same coroutine as doA(). So, technically doA() has completed its execution. To make doA() wait, you have to run doB() and doC() in same coroutine.

suspend fun doA() {
    doB()
}
suspend fun doB() {
    //Do logic here, eventually will call line below
   doC()
}
suspend fun doC() {
    //call api with Flow as the return type
}

Also, do not use async-await if you're using await immediately after async like viewModelScope.async { doB() }.await() because it is same as launch.

Upvotes: 1

Related Questions