Kotlin Coroutines — Exception Handling and Cancellation
It’s very important to handle the exception occurs during the networking operation or any IO operations in kotlin coroutines. So, in this tutorial, we are going to see how to handle the exceptions and how to cancel the particular job running on the kotlin coroutines.
Before getting into this tutorial, If you are not familiar with kotlin coroutines, I strongly recommend you to read another tutorial on kotlin coroutines.
In Kotlin Coroutines, we can handle the exceptions in two ways, one is using the try/catch block, another way is using the CoroutineExceptionHandler. let’s see how to implement both on kotlin coroutines.
Handling Exception With Try / Catch
In this method, we can use try/ catch in the way we are using the kotlin programming. But when we are working with kotlin coroutines, we need to put the try/catch block inside the Coroutine Scope Functions.
fun handleExceptionWithTryCatch() {
viewModelScope.launch() {
try {
val movies = ApiService.getInstance().getAllMovies401()
movieList.postValue(movies)
} catch (e: Exception) {
Log.d("Exception", "${e.message.toString()} handled !")
}
}
}
In the above code, I have created a ViewModelScope, that is Coroutines Scope Function to perform a networking operation. The API call returns 401 Exception, In normal cases, it will crash the application. But we are using try/catch around the API call. So the exception will be handled.
Output:
com.example.kotlincoroutines D/Exception: HTTP 401 401 Unauthorized handled !
Handle Exception And Return Result
In some cases, we need to return the default response when the exception occurs. To do this we need to add the default response in the catch block to return the default response. If we are using multiple operations then we need to use separate try/catch blocks to handle to separately.
fun returnDefaultResultOnException() {
viewModelScope.launch {
try {
val movie1 = try {
ApiService.getInstance().getAllMovies()
} catch (e: Exception) {
listOf()
}
val movie2 = try {
ApiService.getInstance().getAllMovies401()
} catch (e: Exception) {
listOf()
}
Log.d("Movie 1", movie1.toString())
Log.d("Movie 2", movie2.toString())
} catch (e: Exception) {
Log.d("Exception", "${e.message.toString()} handled !")
}
}
}
In the above code, I am called two API calls. The first API call returns a successful response with a list of movies. But the second API call returns 401 exceptions. So, I have handled that API using the try/catch block and returned the empty movie list as a response.
Output:
com.example.kotlincoroutines D/Movie 1: [Movie(category=Latest, imageUrl=https://howtodoandroid.com/images/coco.jpg, name=Coco, desc=Coco is a 2017 American 3D computer-animated musical..
com.example.kotlincoroutines D/Movie 2: []
Handling Exception With CoroutineExceptionHandler
In this way, we need to attach the separate CoroutineExceptionHandler variable and attach this variable to Coroutine Builder. So, when the exception occurs in the coroutine scope it will be forwarded to the exception handler.
private val handler = CoroutineExceptionHandler { _, exception ->
Log.d("Exception", "${exception.message.toString()} handled !")
}
fun handleExceptionWithCoroutineExceptionHandler() {
viewModelScope.launch(handler) {
val moviesList = ApiService.getInstance().getAllMovies401()
movieList.postValue(moviesList)
}
}
In the above code, I have created the CoroutineExceptionHandler variable and attached that variable to ViewModelScope. Now, The API call returns the 401 Exception. So the exception will be directed to the exception handler to handle it.
In this way, we have a generic exception handler and attached the multiple Coroutine Builder.
Output:
com.example.kotlincoroutines D/Exception: HTTP 401 401 Unauthorized handled !
Canceling the Kotlin Coroutine
when the user leaves the screen or user wants to cancel some operation, then we need to cancel the operation running on the coroutine scope. to do this first, we need to create a Coroutine Scope variable called Job. Job used to do operation on coroutines including canceling.
var printingJob: Job? = null
fun startPrint() {
printingJob = viewModelScope.launch {
try {
for (i in 1..1000) {
delay(20)
println(i)
}
} catch (e: Exception) {
Log.d("Exception", "${e.message.toString()} handled !")
} finally {
Log.d("finally", "clear all resources")
}
}
}
fun stopPrint() {
printingJob?.cancel()
}
In the above code, I have created a job variable and by calling the startPrint() function I will set the coroutine scope instance into it. Once started, it will print 1 to 1000 in the delay of 20 milliseconds.
whenever we need to cancel the job need to call the stopPrint() function to call the cancel() on the job.
Output:
com.example.kotlincoroutines I/System.out: 86 com.example.kotlincoroutines I/System.out: 87 com.example.kotlincoroutines I/System.out: 88 com.example.kotlincoroutines I/System.out: 89 com.example.kotlincoroutines I/System.out: 90 com.example.kotlincoroutines D/Exception: Timed out waiting for 2000 ms handled ! com.example.kotlincoroutines D/finally: clear all resources
Timeout on Kotlin Coroutine
Are you want to cancel the particular operation, if it takes a long time to complete in kotlin coroutines. Then you need to run the operation with withTimeout(timeInMilliseconds) function inside the coroutine scope. This will cancel the operation automatically after the defined time is reached.
fun startPrintWithTimeout() {
viewModelScope.launch {
try {
withTimeout(2000) {
for (i in 1..1000) {
delay(20)
println(i)
}
}
} catch (e: Exception) {
Log.d("Exception", "${e.message.toString()} handled !")
}
finally {
Log.d("finally", "clear all resources")
}
}
}
In the above code, I am printing 1 to 1000 numbers in a 20 milliseconds delay inside the ViewModelScope. Also, I have surrounded the printing operation with the withTimeOut(2000) function. So, the printing operation will be canceled after 2000 milliseconds. Also, the printing operation is surrounded by a try/catch block. So the canceled operation with be caught.
Output:
com.example.kotlincoroutines I/System.out: 71 com.example.kotlincoroutines I/System.out: 72 com.example.kotlincoroutines I/System.out: 73 com.example.kotlincoroutines I/System.out: 74 com.example.kotlincoroutines D/Exception: Timed out waiting for 2000 ms handled ! com.example.kotlincoroutines D/finally: clear all resources
you can download this example on Github.
What’s Next:
Conclusion
I hope you learned about the kotlin coroutine and how to handle the exception and cancel the kotlin coroutines. let me know your feedback in the comments.
Originally published at https://howtodoandroid.com on November 25, 2021.