Categories
blog kotlin

Quick introduction to Kotlin coroutines part 2

If you have not read part one of this series, please read it first, it explains the main idea behind Kotlin coroutines.

Error handling

If you read the part one of this series, you may notice that error handling was not covered as a topic at all, so in this post, we will go through techniques you can utilize to handle errors that may occur inside coroutines.

Exceptions

The main idea introduced in part one of this series is the idea of async code written as a synchronous code and if you think about it, how would you handle errors in a sync style code, you catch exceptions. Same idea here, we can surround code that throws an error inside try/catch block, and handle error states in your async code. Let’s see an example of a retrofit network call.
https://gist.github.com/abdurahmanadilovic/21f9d909751d2c7359135dbe575773b4
As we can see in the example above, we surrounded the retrofit method execute with try and catch blocks, and two exceptions are caught that execute method can throw, IOException and RuntimeException. Why just these two exceptions? If you look at the documentation for execute method, you can see that execute method can throw only those two exceptions. In case an exception is thrown, the user will be notified, and that part of the code runs on the main thread.
A better way would be to pass in an exception handler that will be called once the launch coroutine encounters and exception.
https://gist.github.com/abdurahmanadilovic/3e54fe33584498b68fbba2c17ad5e322

Async vs launch builder

In part 1, we mainly used launch coroutine builder as our main coroutine block, and one problem with launch builder is the exception handling, if an exception is not caught inside a coroutine, the whole app will crash. Kotlin provides another coroutine builder, Async builder, which behaves differently in few ways. One way in which it differs is exception handling, async block just ignores thrown exceptions if they are not caught resulting in a non app crash scenario. Here is a way to catch an exception with async block
https://gist.github.com/abdurahmanadilovic/a38b5e4d93fd70adb82eb2a9c9cbe711

Cancellation

What if you need to cancel a coroutine, for example, the android activity gets paused or destroyed, and the coroutine result is no longer needed?

Job

All coroutine builders return a job, which can be canceled at any point by calling job.cancel(). What is interesting with Kotlin coroutines is the ability to specify a parent job as a context for multiple coroutines, and calling cancel() on the parent coroutine will result in all coroutines being canceled, very convinient. In all examples above you may notice the parentJob passed in in every coroutine, and calling parentJob.cancel() inside onPause() activity method results in all coroutines being cancelled.
https://gist.github.com/abdurahmanadilovic/98c185b88fc8f948c06406b51461499f

Hooking into callback code

The last thing I want to talk about is hooking into code that is async but uses callbacks to handle the suspension of the flow. For example, firebase database uses callbacks to inform the caller an operation has completed. In that case, you need to bridge between a Kotlin coroutine and a callback listener. SuspendCoroutine to the rescue! A special coroutine which will be suspended by default, and you call resume on it inside the callback method. Below is an example from one of my apps that uses google firebase as a backend.
https://gist.github.com/abdurahmanadilovic/7ecf111a161faba5cbf2e17eb1922aa5
This getBooleanValue can be used inside any coroutine and will behave as any other suspend function, hence creating a bridge between Kotlin coroutine and callback.

Conclusion

I have created a sample app that uses all exception handling cases shown in this blog post on this Github repository.
If you liked the article share it if you loved it comment below :).

Leave a Reply

Your email address will not be published. Required fields are marked *