Khantahr
Khantahr

Reputation: 8528

Making Kotlin Suspend Function Cancellable

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

Answers (2)

Thracian
Thracian

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

Tenfour04
Tenfour04

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

Related Questions