I want to make a suspend function cancellable, but isActive isn't accessible. Is this just handled automatically?
suspend fun coolFunction() {
while (isActive) {
/* Do cool stuff */
}
}
To cooperate with cancellation, you can periodically suspend, most simply done by calling yield()
suspend fun coolFunction() {
while (true) {
yield()
/* Do cool stuff */
}
}
You can also support cancellation by checking CoroutineScope.isActive. But a suspend function on its own doesn't have direct access to the CoroutineScope it was called from. You would have to use something like coroutineContext[Job]!!.isActive, which is clumsy. isActive is more useful when you're directly composing a coroutine with something like launch rather than a suspend function that could be called from any scope.
You can cancel the job or coroutineScope that suspending function is running in so the suspending function will cancel.
private suspend fun CoroutineScope.cancelComputation() {
println("cancelComputation()")
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
// WARNING 🔥 isActive is an extension property that is available inside
// the code of coroutine via CoroutineScope object.
while (isActive) { // cancellable computation loop
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion println("main: Now I can quit.")
/*
Prints:
cancelComputation()
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
main: I'm tired of waiting!
*/
}