Reputation: 8528
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 */
}
}
Upvotes: 5
Views: 6013
Reputation: 66814
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!
*/
}
Upvotes: 1
Reputation: 93639
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.
Upvotes: 6