Kotlin Coroutines in Android

Tram Ho

Preamble

This article is for anyone who is curious about Coroutines in Kotlin but doesn’t know exactly what it is.

In this tutorial, we will learn Coroutines in Kotlin with the following topics:

  • What exactly is Coroutines?
  • Why is the solution needed by Kotlin Coroutines?
  • Step by step guide on how to deploy Kotlin Coroutines in Android.
  • What is the scope of Corlinines?
  • Exception handling in Kotlin Coroutines.

Reference source: https://blog.mindorks.com/mastering-kotlin-coroutines-in-android-step-by-step-guide

What is coroutines?

Coroutines = Co + Routines Here, Co means collaboration and Routines means functions. Meaning that when the functions work together, we call it Coroutines.

See the example below to understand more about this. Suppose we have 2 functions, functionA and functionB .

functionB

Then we can call functionA as follows:

Here, functionA will execute taskA1 and then give control to functionB to execute taskB1 .

Then functionB will execute taskB1 and return control to functionA to execute taskA2 , etc.

This means that functionA and functionB are working together.

With Kotlin Coroutines, this cooperation can be done very easily without using the when or switch case I used in the above example.

Now, we understand what coroutines are when it comes to collaboration between functions. There are endless possibilities that open because of the collaborative nature of the functions.

Some possibilities are as follows:

  • It can execute a few lines of functionA and then execute a few lines of functionB and then again several lines of functionA , etc. This will be useful when a thread is standing still doing nothing, in which case, it can execute a few lines of another function. In this way, it is possible to take full advantage of the thread . Finally, this collaboration helps in multitasking.
  • It will allow writing asynchronous code in a synchronous way. We will talk about this later in this article.

Overall, Coroutines makes multitasking very easy.

So we can say that both Coroutines and threads are multitasking. But the difference is that threads are managed by the operating system and coroutines by the user because it can execute several functional lines by leveraging collaboration.

It’s an optimization framework written on the actual thread by taking advantage of the collaborative nature of the functions to make it lighter and more powerful. So we can say that Coroutines are lightweight threads. A lightweight thread means that it does not map on the native thread. Therefore, it does not require context switching on the processor, so they are faster.

What does “it doesn’t map on a native thread” mean?

Coroutines is available in many languages. Basically, there are two types of Coroutines:

  • Stacking (Stackful)
  • No stacking (Stackless)

Kotlin implements stackless coroutines – that means coroutines don’t have their own stack, so it doesn’t map on the native thread. Now, you can understand the paragraph below, the official Kotlin website says

One can think of a coroutine as a light-weight thread. Like threads, coroutines can run in parallel, wait for each other and communicate. The biggest difference is that coroutines are very cheap, almost free: we can create thousands of them, and pay very little in terms of performance. True threads, on the other hand, are expensive to start and keep around. A thousand threads can be a serious challenge for a modern machine.

Coroutines do not replace threads, it is like a framework to manage them.

Correct definition of Coroutines: A framework for concurrent management in a simpler and more efficient way with lightweight threads written on top of actual threading framework to make the most of it using the collaborative nature of functions. . We now understand exactly what Coroutines are. So we need to know why we need the solutions that Coroutines Kotlin provides.

Why do you need Kotlin Coroutines?

Let’s take a standard use case of Android Application as follows:

  • Get the User from the server.
  • Display User on UI

When we call fetchAndShowUser function, it will throw to NetworkOnMainThreadException because network call is not allowed on main thread. There are many ways to solve that. Some of them are as follows:

  1. Using Callback : Here, we run fetchUser in the background thread and pass the result to the callback.

  1. Using RxJava: This way we can escape the nested callback.

  1. Using Coroutines:

The above code looks to be synchronized, but not really synchronized. We will find out

Deploy Kotlin Coroutines in Android

Add Kotlin Coroutines dependencies to Android project as shown below:

Now, the fetchUser function will look like below:

And the fetchAndShowUser function will look like this:

And the function showUser below remains the same:

Inside:

  • Dispatchers : Dispatchers help coroutines decide which thread the job is to do. There are three main types of Dispatchers: IO , Default and Main . IO dispatcher is used to perform network and disk-related tasks. Default is used to do CPU intensive work. Main is the UI thread of Android. To use them, we need to wrap the work under the async function. The Async function looks like below.

  • suspend : The suspend function is a function that can start, pause and resume.

Suspend functions are only allowed to be called from another coroutine or other suspend function. You can see that the async function includes the keyword suspend . Therefore, to use it, we also need to implement the suspend function.

So fetchAndShowUser can only be called from another suspend function or coroutine. We cannot perform the onCreate of an suspend activity, so we need to call it from the coroutines as shown below:

showUser will run on the UI thread because we used Dispatchers.Main to launch it.

There are two functions in Kotlin to start coroutines as follows:

  • launch{}
  • async{}

Launch and Async in Kotlin Coroutines

The difference is that launch{} doesn’t return anything and async{} returns a Deferred<T> , where the await() function returns the coroutine result as we have the future in Java, executing the future. get () to get the result.

Another way to say:

  • launch : Done then forgotten
  • async : Perform a task and return a result

Take an example to learn Launch and Async.

We have a fetchUserAndSaveInDatabase function as shown below:

Now, we can use launch as below:

Because fetchUserAndSaveInDatabase doesn’t return anything, we can use launch to complete the task and then do something on the Main Thread.

But when we need results back, we need to use async .

We have two functions that return the User as below:

Now, we can use async as shown below:

Here, it makes both network calls parallel, waits for the results, and then calls the showUsers function.

We now understand the difference between Launch and Async.

Next we will talk about withContext .

withContext is nothing more than an async way of writing that we don’t have to write await () .

But there are many more things we should know about withContext and await.

Now, let’s use withContext in our async example of fetchFirstUser and Now, let’s use withContext in our async example of fetchFirstUser and fetchSecondUser in parallel.

When we use withContext , it will run in sequence instead of in parallel. That is a big difference.

Rule:

  • Use withContext when you don’t need to execute it in parallel.
  • Only use async when you need to execute in parallel.
  • Both withContext and async can be used to get results, not with launch .
  • Use withContext to return the result of a task.
  • Using async results from multiple tasks running in parallel.

Scope of Kotlin Coroutines

Scope in Kotlin Coroutines is very useful because we need to cancel the background task as soon as the activity is canceled. Here, we will learn how to use scope to handle these types of situations.

Assuming our activity is scope, the background task will be canceled as soon as the activity is canceled.

In the activity, we need to implement CoroutineScope.

In the onCreate and onDestroy function.

For now, just use the launch like below:

As soon as the activity is canceled, the task will be canceled if it is running because we defined the scope.

When we need global scope is our application scope, not the activity scope, we can use GlobalScope as follows:

Here, even if the operation is canceled, the fetchUser functions will continue to run because we have used GlobalScope .

This is how Scopes in Kotlin Coroutines become useful.

Exception handling in Kotlin Coroutines.

When using launch

One way is to use try-Catch:

The alternative is to use a handler

To do so we need to initialize an exception handler as follows:

Then attach this handler as follows

If there is an exception in fetchUserAndSaveInDatabase , it will be handled in the handler we just attached.

When using activity scope, we can attach exception to coroutineContext as follows:

and use:

When Using async

When using async, we need to use the try-catch block to handle the exception below.

Now, let’s look at some more practical use cases of exception handling in Android Development.

Let’s say we have two network calls as below:

  • getUsers()
  • getMoreUsers()

And, we are making network calls in sequence as below:

If one of the network calls fails, it will go directly to the catch block.

But suppose we want to return an empty list for a failed network call and continue with the response from another network call. We can add try-catch blocks to individual network calls as below:

This way, if an error occurs, it will continue with the empty list.

Now, if we want to make network calls in parallel. We can write code like below using async .

Here, we will face a problem, if the network error returns, the app will crash! , it will not be able to reach the catch block.

To solve this problem, we will use coroutineScope as follows:

Now no matter which network error it occurs, it will reach the catch block.

As suppose again, we want to return an empty list for the failed network call and continue waiting for the response from the other network call. We will need to use the supervisorScope and add try-catch blocks to each individual network call as follows:

Thus, this way even if an error occurs, it will continue with an empty list.

This is how the supervisorScope works.

Conclude

  • When Not using async , we can still continue with try-catch or CoroutineExceptionHandler and achieve whatever you want with each case.
  • When using async , in addition to try-catch , we still have 2 more options coroutineScope and supervisorScope
  • With async using the supervisorScope with each individual try-catch of each task, within the outer try-catch block, you can continue other tasks even if one of them fails.
  • For async , use coroutineScope with the outer try-catch block, when you don’t want to continue with other tasks when one of them fails.

This is an example git of Coroutines author. Please refer to it

https://github.com/MindorksOpenSource/Kotlin-Coroutines-Android-Examples

Share the news now

Source : Viblo