'Cancel viewModelScope and re-use it later on

I'm using Coroutines for dealing with async jobs:

viewModelScope.launch {
    val userResponse = getUsers() //suspendable function 
}

What I want to do is stop all existing/ongoing coroutine jobs. Idea is that I click on different tabs. If getUsers() takes up to 5 seconds and user clicks from User tab to Job tab, I want that existing API call is stopped and response is not observed.

I tried to do viewModelScope.cancel(), but that seems not to be working.

Question is - how to cancel existing jobs on button click?



Solution 1:[1]

Define a reusable Job like following in the ViewModel class:

private var job = Job()
    get() {
        if (field.isCancelled) field = Job()
        return field
    }

Pass it to all of launch coroutine builders as the parent Job:

viewModelScope.launch(job) {
    val userResponse = getUsers()
}

viewModelScope.launch(job) {
    // some other work
}

...

On button click, just cancel the parent job:

fun cancelAll() {
    job.cancel()
}

Solution 2:[2]

You can get its Job through its CouroutineContext like this:

viewModelScope.coroutineContext[Job]

To stop all existing/ongoing coroutine jobs you can call its cancel method:

viewModelScope.coroutineContext[Job]?.cancel()

If you need to start other coroutines eventually then call its cancelChildren method instead:

viewModelScope.coroutineContext[Job]?.cancelChildren()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 aminography
Solution 2 Glenn Sandoval