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.

Kotlin Coroutines for Android Development


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:

Kotlin High Order Functions and Lambdas Explained

Kotlin Scope Functions Explained [Example]

koin – Dependency Injection In Android

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.

Leave a Reply

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