Subodh Nijsure
Subodh Nijsure

Reputation: 3453

Cancel all pending Kotlin jobs from ViewModel's onCleared

With Kotlin 1.3 one can launch job using GlobalScope.launch but one thing that I can't seem to figure out is how to keep track of Job returned by ``GlobalScope.launch` and cancel all pending jobs if they are active.

In older version of launch one could specify parent = parentJob and one could simply cancel parentJob. But when using GlobalScope.launch how does one cancel all pending jobs (easily) so from say ViewModel's onCleared one can cancel all pending stuff.

Upvotes: 1

Views: 1563

Answers (2)

Sergio
Sergio

Reputation: 30665

Using GlobalScope is highly discouraged. In the Android KTX libraries there are handy scopes that can be used to launch coroutines. Using them you don't need to think about cancelling jobs, they designed to do it by themselves. CoroutineScopes:

  • In ViewModel class it is viewModelScope. The CoroutineScope is bound to Dispatchers.Main and is automatically cancelled when the ViewModel is cleared. You can use viewModelScope instead of creating a new scope for each ViewModel. Dependency:

    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
    
  • In Activity/Fragment there is lifecycleScope. Any coroutine launched in this scope is canceled when the Lifecycle is destroyed. You can access the CoroutineScope of the Lifecycle by using the lifecycle.coroutineScope or lifecycleOwner.lifecycleScope properties. Dependency:

    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
    

Example of launching a coroutine in ViewModel:

viewModelScope.launch {...}

Upvotes: 1

Subodh Nijsure
Subodh Nijsure

Reputation: 3453

So basically it turns out you can either have your ViewModel/AppComptActivity etc. inherit from CoroutineScope. Or you can use composition like this:

```

private val pendingJobs = Job()
private val coroutineScope = CoroutineScope(contextProvider.io + pendingJobs)

...
...

    coroutineScope.launch  {

    withContext(contextProvider.UI) {

    }
    }

```

Then in appropriate destroy method call pendingJobs.cancel() to terminate pending jobs.

Upvotes: 3

Related Questions