androidkotlinmvvmkotlin-coroutinesandroid-viewmodel

How do nested jobs launched in the viewModelScope work?


I am new to the Koltin coroutine and sometimes it gets confusing. Let's suppose that in my View Model I am collecting a flow as follows:

viewModelScope.launch A@{
    uiState.collect { state ->
        // Do something
    }
}

The block A is supposed to collect the states as long as viewModelScope is available. Now, what if I want to launch another job inside the collect block?

I think if I do it like this

var jobBAlreadyLaunched = false
viewModelScope.launch A@{
    uiState.collect { state ->
        if (state.isOk && !jobBAlreadyLaunched) {
             launch B@{
                 anotherState.collect { res->
                     jobBAlreadyLaunched = true
                 }
            }
        }
    }
}

the block B will get cancelled if the job A cancels. So I changes my code to this:

var jobCAlreadyLaunched = false
viewModelScope.launch A@{
    uiState.collect { state ->
        if (state.isOk && !jobCAlreadyLaunched) {
             viewModelScope.launch C@{
                 anotherState.collect { res->
                     jobCAlreadyLaunched = true
                 }
            }
        }
    }
}

In this case, I think the block C is bound to the viewModelScope and is independent from the block A's coroutine scope so the coroutine C will continue working as long as viewModelScope is active. Is that concept generally correct?

I want to launch the coroutine C once state.isOk is true and let it collect the res updates until the view model is active but I am not sure whether this implementation is correct.

I think if the block C gets suspended it won't suspend the block A. Is that correct?

Many thanks for your help.


Solution

  • Your description of the different behaviors between B and C is correct.

    B is a child coroutine of A, so it will be canceled when A is cancelled. Also, the job A will not be complete until B is complete.

    C is a sibling coroutine of B and will run completely independently. Since viewModelScope is constructed using a SupervisorJob, A and C can fail independently from each other.

    I think if the block C gets suspended it won't suspend the block A. Is that correct?

    Correct. This is also essentially true for B, except that when A gets to the end of its launch lambda, it will still be waiting for the launched B to complete before it is considered complete.