Kotlin Coroutines By Example (Exception Handling, Delay, Timeout & More)

Introduction
Coroutines are a simple way to implement asynchronous and non-blocking code. It's implemented using suspending functions at the language level and with the help of the kotlinx.coroutines library.
Coroutine scopes and builders are used to define Coroutines.
To better understand Kotlin Coroutine concepts such as suspending functions, builders, scopes and contexts, you can follow this previously posted article.
Execute code in the background and continue
import kotlinx.coroutines.*
fun main() {
    println("The main program is started")
    GlobalScope.launch {
        println("Background processing started")
        delay(500L)
        println("Background processing finished")
    }
    println("The main program continues")
    runBlocking {
        delay(1000L)
        println("The main program is finished")
    }
}
Concurrent code execution
Launch multiple computations in parallel and wait for them to finish
import kotlinx.coroutines.*
import java.text.SimpleDateFormat
import java.util.*
fun main() = runBlocking {
    val deferred1 = async { computation1() }
    val deferred2 = async { computation2() }
    printCurrentTime("Awaiting computations...")
    val result = deferred1.await() + deferred2.await()
    printCurrentTime("The result is $result")
}
suspend fun computation1(): Int {
    delay(1000L) // simulated computation
    printCurrentTime("Computation1 finished")
    return 131
}
suspend fun computation2(): Int {
    delay(2000L)
    printCurrentTime("Computation2 finished")
    return 9
}
fun printCurrentTime(message: String) {
    val time = (SimpleDateFormat("hh:mm:ss")).format(Date())
    println("[$time] $message")
}
Cancelling a coroutine execution
import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        // Emulate some batch processing
        repeat(30) { i ->
            println("Processing $i ...")
            delay(300L)
        }
    }
    delay(1000L)
    println("main: The user requests the cancellation of the processing")
    job.cancelAndJoin() // cancel the job and wait for it's completion
    println("main: The batch processing is cancelled")
}
Execution timeout
Run a given block of code inside a coroutine with a specified timeout.
Throw exception on timeout
A TimeoutCancellationException is thrown if the timeout is exceeded.
import kotlinx.coroutines.*
fun main() = runBlocking {
    withTimeout(1000L) {
        repeat(30) { i ->
            println("Processing $i ...")
            delay(300L)
        }
    }
}
Return null on timeout
import kotlinx.coroutines.*
fun main() = runBlocking {
    val status = withTimeoutOrNull(1000L) {
        repeat(30) { i ->
            println("Processing $i ...")
            delay(300L)
        }
        "Finished"
    }
    println("The processing return status is: $status")
}
Exception handling
When using launch
By default, the exceptions thrown inside a coroutine started with launch don't require to be handled and are printed instead to the console. They are treated as uncaught exceptions.
However, they still can be handled by using a CoroutineExceptionHandler.
import kotlinx.coroutines.*
fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, exception ->
        println("$exception handled !")
    }
    val job = GlobalScope.launch(handler) {
        throw UnsupportedOperationException()
    }
    job.join()
}
When using async
import kotlinx.coroutines.*
fun main() = runBlocking {
    val deferred = GlobalScope.async {
        // some business logic
        throw UnsupportedOperationException()
    }
    try {
        deferred.await() // The exception is thrown here
        println("Won't be printed")
    } catch (e: UnsupportedOperationException) {
        println("UnsupportedOperationException handled !")
    }
}
Android usage
Setup
To be able to launch coroutines with the Dispatchers.Main context, you have to add the kotlinx-coroutines-android dependency to your project. For example, when using Gradle, add the following line to your app/build.gradle file inside your dependencies:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1"
Examples
Coroutines are commonly used on View Models to fetch data from a database or from the Internet.
import androidx.lifecycle.*
import kotlinx.coroutines.*
// Android View Model (holds data to be displayed in a view)
class MyViewModel : ViewModel() {
    private val _properties = MutableLiveData<List<MyData>>()
    val properties: LiveData<List<MyData>>
        get() = _properties
    // To be able to cancel launched coroutines (if any)
    private val job = Job()
    // The coroutine runs using the Main (UI) dispatcher
    private val coroutineScope = CoroutineScope(job + Dispatchers.Main)
    init {
        coroutineScope.launch {
            val deferred: Deferred<List<MyData>> = MyService.getPropsAsync()
            _properties.value = deferred.await()
        }
    }
    // Cancel the job when the view model is destroyed
    override fun onCleared() {
        super.onCleared()
        job.cancel()
    }
}