A job whose execution has ended due to cancellation or an unhandled exception is considered cancelled. When a job has been cancelled, the information about the cancellation can be obtained through the getCancellationException() function. This function will return a CancellationException, which can be used to retrieve information such as the cause of the cancellation, if it was set. Here's an example:
fun main(args: Array<String>) = runBlocking {
val job = launch {
delay(5000)
}
delay(2000)
// cancel
job.cancel(cause = Exception("Tired of waiting"))
val cancellation = job.getCancellationException()
cancellation.cause // Exception("Tired of waiting")
}
In order to differentiate between a job that was cancelled and one that failed due to exception, you are encouraged to set a CoroutineExceptionHandler to it and process the cancellation there, as shown:
fun main(args: Array<String>) = runBlocking {
val exceptionHandler = CoroutineExceptionHandler {
_: CoroutineContext, throwable: Throwable ->
println("Job cancelled due to ${throwable.message}")
}
launch(exceptionHandler) {
TODO("Not implemented yet!")
}
delay(2000)
}
You can also use invokeOnCompletion(), as follows:
fun main(args: Array<String>) = runBlocking<Unit> {
launch {
TODO("Not implemented yet!")
}.invokeOnCompletion { cause ->
cause?.let {
println("Job cancelled due to ${it.message}")
}
}
delay(2000)
}