Since the beginnings of mobile programming, developers have always had to be careful about resource optimization when processing multiple tasks in parallel but without blocking the main thread of our application.
To make a small review of basic concepts, it is important to mention that in any mobile application we have a main thread in which it is possible to interact with the components of the user interface. But in most cases this is not enough since in order to load our application with the corresponding information to be displayed, it will be necessary to have a strategy that allows us to go and find all the necessary information and then display it appropriately to the users so they can have the best possible experience regarding to performance.
What makes a user have an awesome experience with an app?
This point is quite important since a user wants to interact with a mobile application fluently and without having idle times with eternal progress dialogs or loading indicators.
Assuming that we have a well built backend server infrastructure… What would be the most appropriate way to communicate with web services from the client side so the information can be displayed on the screen as soon as possible using best performance techniques?
Actually, if we talk about communication with web services, in this case several factors can influence:
• Call handling techniques and asynchronous event processing.
• Number of calls to services necessary to obtain the information.
• Level of extension and data to be processed.
Let’s talk a little history on Android:
In the early days of Android there was a lot of talk about asynchronous task processing using async tasks. These async tasks allow background work to be performed without involving the main thread of the application and thus prevent the user interface from crashing due to the time consumed in processing them. Once the task has a result, the async task drifts into the main thread to allow the programmer to continue his work in the main thread, such as updating the UI with the corresponding data.
What are the newest techniques in Android for multithreading and asynchronous processing?
Currently the development of applications that connect with web services and perform tasks in parallel is more than common, therefore there are techniques that allow handling this type of situation. This time we will talk about “Coroutines”
What are coroutines?
To mention it in a simple and fast way, we could say that they are similar to “threads” but with many additional improvements.
Coroutines allow the programmer to write code sequentially.
Can I run multiple coroutines at the same time?
Of course! The idea is that several coroutines can be executed at the same time and optimize the parallel processing of tasks asynchronously.
How do coroutines work?
• Coroutines run within suspend functions.
• Suspend features allow you to suspend work and then resume it when needed
• If several coroutines are being executed at the same time then we can wait for all of them to finish their execution to be notified and thus continue with more tasks.
Now let’s study a concrete example of Coroutines implementation!
fun startCoroutines() {
job = GlobalScope.launch(Dispatchers.IO) {
withContext(Dispatchers.IO) { getCategories() }
val time = measureTimeMillis {
try {
coroutineScope {
val answerGetClient = async { getClient() }
val answerGetRewardPoints = async { getRewardPoints() }
val result = answerGetClient.await()
val result2 = answerGetRewardPoints.await()
if (result.data != null && result2.data != null) {
setupClientInfo(result)
setupRewardPoints(result2)
withContext(Dispatchers.Main) {
view?.initializeSDK()
}
}
}
} catch (e: Throwable) {
withContext(Dispatchers.Main) {
view?.showGenericError()
}
Log.d("ERROR", " ${e.message}")
}
}
}
}
Let’s explain a little the code studied above!
The startCoroutines function contains code where 3 tasks are executed asynchronously!
• getCategories ()
• getClient ()
• getRewardPoints ()
Execution steps:
1) By calling GlobalScope.launch (Dispatchers.IO) we are indicating that we are going to trigger the execution of the internal code block within a general scope but using a specific dispatcher. A dispatcher is similar to a thread, and we can indicate, for example, the following:
Dispatcher Main for UI operations
Dispatcher IO for networking and database operations
Dispatcher Default for long calculations that may block the main thread.
2) Then calling withContext (Dispatchers.IO) {getCategories ()} we are indicating that we trigger the execution of the first task in a separate thread.
3) Below we can see a coroutineScope block where within it you can see two tasks invoked to be executed but with the word “async”. In this case, what you are doing is triggering the execution of two different tasks asynchronously and then waiting for the results with the word “await”
4) Thanks to the ability of coroutines to parallelize the processing and return a result when they are ready we can see that below the conditional of the if statement that verifies the result and result2. This conditional is only going to be executed when both results are ready and contain a value. This behavior is done thanks to the combination of “async” + “await”
5) Finally the Main dispatcher is used to execute code in the main thread and update the UI.
Conclusion
Nowadays coroutines have become more popular and adopted by Android developers when programming.
Never forget that there are key concepts that every developer has to take into account to be sure that coroutines are being used in a correct way to avoid memory leaks or infinite loops of tasks execution.
To summarize it is highly recommended to implement coroutines for async programming operations following good practices using contexts and dispatchers according to the required needs.
Scalable projects are becoming more popular built with MVVM + coroutines technologies.