Software Development

Common Coroutine Mistakes

admin
8 September 2022

Common Coroutine Mistakes

1. Incorrect exception handling.

				
					fun foo() { try { viewModelScope.launch { throw Exception() } } catch (e: Exception) { e.printStackTrace() } }
				
			
In this function, we are trying to catch an exception outside the coroutine thrown inside the coroutine. Ideally, we are supposed to handle exceptions inside the launch block because it will get cancelled and will not send the exception to the parent where the coroutine was declared. There are two ways to fix this First, handle the exception inside the coroutine-
				
					fun foo() {
    viewModelScope.launch {
        try {
            throw Exception()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}
				
			

Second, use a CoroutineExceptionHandler() –

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

fun foo() {
    viewModelScope.launch(coroutineExceptionHandler) {
        throw Exception()
    }
}
				
			

2. Making suspend functions main safe

It is recommended that we perform network calls or heavy operations on background thread so we do not freeze the UI and risk causing ANR. To assign a thread to a job coroutine uses Dispatchers. Most commonly used dispatchers are Main(assigns main thread) and IO(assigns background thread) suspend
				
					fun foo() {
   //network call or heavy operations 
}
fun callFoo(){
   viewModelScope.launch{
      foo()
   }
}
				
			

By default coroutine assigns main thread to all jobs. So in above example the foo() will block the main thread and can cause ANR. To avoid this we need to tell the coroutine to use the IO dispatcher and we can do that with the help of a suspend function called withContext(). suspend

				
					fun foo() {
   withContext(Dispatchers.IO){
       //network call or heavy operations 
   }
}
fun callFoo(){
    viewModelScope.launch{
        foo()
    }
}
				
			

Above example demonstrate how to ensure execution of any suspend function responsible for network calls or heavy operations on IO thread by just wrapping the function in withContext(Dispatchers.IO). Even when this suspend function gets called from Main dispatcher, the withContext(Dispatchers.IO) will always execute on background thread. I hope this helps you understand coroutines even better. Please let me know some of the coroutines mistakes that you think are also common. Happy coding!

In this function, we are trying to catch an exception outside the coroutine thrown inside the coroutine. Ideally, we are supposed to handle exceptions inside the launch block because it will get cancelled and will not send the exception to the parent where the coroutine was declared. There are two ways to fix this First, handle the exception inside the coroutine- fun foo() { viewModelScope.launch { try { throw Exception() } catch (e: Exception) { e.printStackTrace() } } } Second, use a CoroutineExceptionHandler() - private val coroutineExceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable -> throwable.printStackTrace() } fun foo() { viewModelScope.launch(coroutineExceptionHandler) { throw Exception() } } 2. Making suspend functions main safe It is recommended that we perform network calls or heavy operations on background thread so we do not freeze the UI and risk causing ANR. To assign a thread to a job coroutine uses Dispatchers. Most commonly used dispatchers are Main(assigns main thread) and IO(assigns background thread) suspend fun foo() { //network call or heavy operations } fun callFoo(){ viewModelScope.launch{ foo() } } By default coroutine assigns main thread to all jobs. So in above example the foo() will block the main thread and can cause ANR. To avoid this we need to tell the coroutine to use the IO dispatcher and we can do that with the help of a suspend function called withContext(). suspend fun foo() { withContext(Dispatchers.IO){ //network call or heavy operations } } fun callFoo(){ viewModelScope.launch{ foo() } } Above example demonstrate how to ensure execution of any suspend function responsible for network calls or heavy operations on IO thread by just wrapping the function in withContext(Dispatchers.IO). Even when this suspend function gets called from Main dispatcher, the withContext(Dispatchers.IO) will always execute on background thread. I hope this helps you understand coroutines even better. Please let me know some of the coroutines mistakes that you think are also common. Happy coding!

Table of Contents

Recent Comments
    May 2024
    M T W T F S S
     12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
    Tags:
    androidcoroutineskotlinmobile app development
    1 like
    Leave a Comment
    Share:
    Social