Safely Launch Exception-Ready Coroutines
Tags: android, kotlin, coroutines
Published: 2020-03-11 20:52:36

---
title: Safely Launch Exception-Ready Coroutines
published: true
description: Easily handle coroutine exceptions thrown from coroutine scopes.
tags: android, kotlin, coroutines
cover_image: https://images.unsplash.com/photo-1516849841032-87cbac4d88f7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=3000&q=80
---

Launching `suspend` functions in Kotlin can be a complicated affair. Managing your `CoroutineScope` and making sure exceptions are handled properly can be confusing and easy to forget.

In Android, when using the `ViewModel` or `Lifecycle` specific scopes this gets much easier. We let the Android system provide a `CoroutineScope` and manage killing our coroutines when the lifecycle of those things end.

```kotlin
fun getObjectFromNetwork() {
  viewModelScope.launch {
    val response = networkRepository.getObject()
  }
}
```

However, there are cases when exceptions can be thrown from the `CoroutineScope`. A real life example I experienced recently was a `SocketTimeoutException` that was thrown from a Retrofit call I was making using a `suspend` function. The result is [an Android app crash](https://github.com/Kotlin/kotlinx.coroutines/issues/753), which is definitely not desired when network calls can result in many different thrown exceptions.

The Kotlin [`CoroutineExceptionHandler`](https://kotlinlang.org/docs/reference/coroutines/exception-handling.html#coroutineexceptionhandler) can help us more easily handle exceptions thrown from our Coroutine scope, but it requires us to register the exception handler when we `launch` a new coroutine so we [properly handle nested exceptions](https://proandroiddev.com/managing-exceptions-in-nested-coroutine-scopes-9f23fd85e61).

```kotlin
val coroutineExceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
  // handle thrown exceptions from coroutine scope
  throwable.printStackTrace()
}

fun getObjectFromNetwork() {
  viewModelScope.launch(coroutineExceptionHandler) {
    val response = networkRepository.getObject()
  }
}
```

Now, while the `ViewModel` is probably a logical place for handling exceptions in network calls, there are a lot of exceptions that are thrown irregularly from your app that aren't part of the logical flow of a network call. Using Retrofit as an example, most network calls should return a [`Response`](https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html) with a `body()` or `errorBody()` to handle instead of edge-cases where actual exceptions, like a `SocketTimeoutException` is thrown. It might be worth it to you to abstract this error handling away from your `ViewModel` to help minimize boiler plate.

To try this out, let's leverage the power of Kotlin extensions to create a `safeLaunch` method on `CoroutineScope` that can apply a default `CoroutineExceptionHandler`.

```kotlin
fun CoroutineScope.safeLaunch(launchBody: suspend () -> Unit): Job {
  val coroutineExceptionHandler = CoroutineExceptionHandler { 
  coroutineContext, throwable ->
    // handle thrown exceptions from coroutine scope
    throwable.printStackTrace()
  }
  
  return this.launch(coroutineExceptionHandler) { 
    launchBody.invoke() 
  }
}
```

Now, we can call `safeLaunch` on any `CoroutineScope`, like our `viewModelScope`, to launch a coroutine with this default error handling behavior.

```kotlin
fun getObjectFromNetwork() {
  viewModelScope.safeLaunch {
    val response = networkRepository.getObject()
  }
}
```

There you have it! A nicely-encapsulated method to launch `suspend` functions knowing that we won't see random app crashes because of an unhandled `Throwable`.

--- 

If we wanted `safeLaunch` to be the core `CoroutineScope` launch method in our app, we can even improve the extension a bit to allow users the flexibility of passing their own `CoroutineExceptionHandler` instead of using the default.

```kotlin
val coroutineExceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->   
  throwable.printStackTrace()
}

fun CoroutineScope.safeLaunch(
  exceptionHandler: CoroutineExceptionHandler = coroutineExceptionHandler,
  launchBody: suspend () -> Unit
): Job {  
  return this.launch(exceptionHandler) { 
    launchBody.invoke() 
  }
}
```

---

The same day I wrote this article, [Manuel Vivo](https://medium.com/@manuelvicnt) and [Florina Muntenescu](https://medium.com/@florina.muntenescu) from the Android developer relations team released a really good series on coroutines, including the subject of coroutine exceptions. Check it out if you want to learn more about coroutines and how to manage them.

1. [Intro to Coroutines](https://medium.com/androiddevelopers/coroutines-first-things-first-e6187bf3bb21)
2. [Cancelling Coroutines](https://medium.com/androiddevelopers/cancellation-in-coroutines-aa6b90163629)
3. [Exceptions in Coroutines](https://medium.com/androiddevelopers/exceptions-in-coroutines-ce8da1ec060c)

*[X-post from ajkueterman.dev](https://ajkueterman.dev/posts/safely-launch-exception-ready-coroutines/)*