this is ironic re: my previous question - is this ...
# coroutines
z
this is ironic re: my previous question - is this a good way to run a piece of suspending code under a scope immediately when it’s cancelled?
Copy code
private val onCleared = CompletableDeferred<Unit>()
init {
    // logout in `onCleared()`
    scope.job.invokeOnCompletion {
        onCleared.complete(Unit)
    }
    scope.launch {
        withContext(NonCancellable) {
            onCleared.await()
            // run a piece of suspending code when 
            // the `scope` above is cancelled 
            // (this correlates to a `ViewModel#onCleared`)
        }
    }
}
f
This will not work because scope will never complete as coroutine launched by scope.launch will never terminate (blocked execution if
withContext
). Scopes are not constrains that you need to workaround, are there to help you create structure in your code. Conceptually it doesn't make sense to execute code on a scope that is completed, so trying to make it happen is an anti pattern. Consider using a scope that outlives the execution of your code, or if you want to opt out of structured concurrency just use GlobalScope. The proposed workaround is not better than GlobalScope.
z
Oh good point. Inject an additional scope and leverage that one separately once one scope completes
s
Typically I’d do this with `try`/`finally`. You shouldn’t need to worry about the scope.
Copy code
scope.launch {
    try {
        awaitCancellation()
    } finally {
        withContext(NonCancellable) {
            cleanup()
        }
    }
}