Created
June 30, 2020 16:42
-
-
Save erikhuizinga/c82a404d76c52b6959248ccbb377999f to your computer and use it in GitHub Desktop.
Demo of Kotlin coroutine crash machinery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import kotlinx.coroutines.CoroutineExceptionHandler | |
import kotlinx.coroutines.CoroutineScope | |
import kotlinx.coroutines.Job | |
import kotlinx.coroutines.SupervisorJob | |
import kotlinx.coroutines.async | |
import kotlinx.coroutines.delay | |
import kotlinx.coroutines.launch | |
import kotlinx.coroutines.runBlocking | |
fun main() = | |
try { | |
demo1JustCrash() | |
// demo2JustCrash() | |
// demo3JustCatch() | |
// demo4AwaitCrashOrCancel() | |
// demo5AwaitCrashOrCancel() | |
// demo6AwaitHandleCrash() | |
println() | |
println("Your app finished successfully! ๐") | |
} catch (t: Throwable) { | |
println() | |
println("Your app crashed! ๐ฐ") | |
println(t) | |
println() | |
println( | |
""" | |
๐พ ๐พ ๐พ ๐พ | |
๐พ GAME OVER ๐พ | |
๐พ ๐พ ๐พ ๐พ | |
""".trimIndent() | |
) | |
} | |
suspend fun crash(): Any? { | |
delay(500) | |
throw Throwable("๐ฅ") | |
} | |
fun handle(throwable: Throwable) = println("OK, handled: $throwable") | |
fun demo1JustCrash() { | |
printDemo(1) | |
val scope = CoroutineScope(Job()) | |
val job = scope.launch { crash() } | |
// Ensure we don't continue before all coroutines complete | |
runBlocking { job.join() } | |
/* Where did the exception go? Who caught it? */ | |
} | |
fun demo2JustCrash() { | |
printDemo(2) | |
val scope = CoroutineScope(Job()) | |
val deferred = scope.async { crash() } | |
// Ensure we don't continue before all coroutines complete | |
runBlocking { deferred.await() } | |
/* Where did the exception go? Who caught it? */ | |
} | |
fun demo3JustCatch() { | |
printDemo(3) | |
val scope = CoroutineScope(Job()) | |
val job = scope.launch { | |
// Just catch inside your coroutine body | |
try { | |
crash() | |
} catch (t: Throwable) { | |
handle(t) | |
} | |
} | |
val deferred = scope.async { | |
// Just catch inside your coroutine body | |
try { | |
crash() | |
} catch (t: Throwable) { | |
handle(t) | |
} | |
} | |
// Ensure we don't continue before all coroutines complete | |
runBlocking { | |
job.join() | |
deferred.await() | |
} | |
} | |
fun demo4AwaitCrashOrCancel() { | |
printDemo(4) | |
val parentJob = Job() | |
val scope = CoroutineScope(parentJob) | |
// Obtain a future value | |
val deferred = scope.async { crash() } | |
// Await it in another coroutine | |
val awaitJob = scope.launch { deferred.await() } | |
// Ensure we don't continue before all coroutines complete | |
runBlocking { awaitJob.join() } | |
/* Where did the exception go? Who caught it? */ | |
/* What will the following print? */ | |
println("isActive = ${parentJob.isActive}") | |
println("isCancelled = ${parentJob.isCancelled}") | |
println("isCompleted = ${parentJob.isCompleted}") | |
} | |
fun demo5AwaitCrashOrCancel() { | |
printDemo(5) | |
val parentJob = SupervisorJob() | |
val scope = CoroutineScope(parentJob) | |
// Obtain a future value | |
val deferred = scope.async { crash() } | |
// Await it in another coroutine | |
val awaitJob = scope.launch { deferred.await() } | |
// Ensure we don't continue before all coroutines complete | |
runBlocking { awaitJob.join() } | |
/* Where did the exception go? Who caught it? */ | |
/* What will the following print? */ | |
println("isActive = ${parentJob.isActive}") | |
println("isCancelled = ${parentJob.isCancelled}") | |
println("isCompleted = ${parentJob.isCompleted}") | |
/* What will the following print? */ | |
println("isActive = ${awaitJob.isActive}") | |
println("isCancelled = ${awaitJob.isCancelled}") | |
println("isCompleted = ${awaitJob.isCompleted}") | |
} | |
fun demo6AwaitHandleCrash() { | |
printDemo(6) | |
val parentJob = SupervisorJob() | |
val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception -> | |
println("Coroutine exception handler: $exception") | |
} | |
val scope = CoroutineScope(parentJob + coroutineExceptionHandler) | |
// Obtain a future value | |
val deferred = scope.async { crash() } | |
// Await it in another coroutine | |
val awaitJob = scope.launch { deferred.await() } | |
// Ensure we don't continue before all coroutines complete | |
runBlocking { awaitJob.join() } | |
/* Where did the exception go? Who caught it? */ | |
/* What will the following print? */ | |
println("isActive = ${parentJob.isActive}") | |
println("isCancelled = ${parentJob.isCancelled}") | |
println("isCompleted = ${parentJob.isCompleted}") | |
/* What will the following print? */ | |
println("isActive = ${awaitJob.isActive}") | |
println("isCancelled = ${awaitJob.isCancelled}") | |
println("isCompleted = ${awaitJob.isCompleted}") | |
} | |
private fun printDemo(n: Int) { | |
println() | |
println("Demo $n") | |
println() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment