Kotlin Coroutines: Better Thread Management And Efficient Approach to Asynchronous Programming in Android
Introduction
In this blog, we will provide an overview of Kotlin Coroutines and also compare and contrast it with Async tasks and Handlers. Async Task and Kotlin Coroutines are two mechanisms that allow developers to perform tasks asynchronously in Android. Async Task is a framework provided by Android that allows developers to run code in the background and update the UI thread with the results. On the other hand, Kotlin Coroutines are a library that provide a more efficient and powerful way to perform asynchronous tasks in Kotlin. They were designed to improve upon the limitations of Async Task and offer a more modern and flexible approach to asynchronous programming in Android. Both Async Task and Kotlin Coroutines can be used to perform tasks such as network requests, database operations, and other long-running processes in the background, without blocking the main thread. However, Kotlin Coroutines offer a number of advantages over Async Task, including improved performance, easier error handling, and a more concise and expressive syntax.
Overview of Kotlin Coroutines
Kotlin Coroutines are a powerful tool for concurrent and asynchronous programming in the Kotlin language. Coroutines allow you to write code that is non-blocking and can pause execution without blocking a thread, making it more efficient and scalable than traditional thread-based concurrency.
One of the key advantages of Kotlin Coroutines is that they make it easy to write asynchronous code in a sequential and readable manner. This is because coroutines use suspending functions, which can suspend their execution without blocking a thread, and can be resumed at a later time. This allows you to write asynchronous code in a way that looks and feels like synchronous code.
Another advantage of Kotlin Coroutines is their ability to manage complex concurrent systems with a small amount of code. Coroutines can be composed and chained together, making it easy to create complex and scalable concurrent systems without the need for complex synchronization mechanisms.
Overall, Kotlin Coroutines are a powerful and versatile tool for concurrent and asynchronous programming in Kotlin. They make it easy to write efficient and scalable code.
Why Not Async Tasks and Handlers??
Async tasks and handlers are not necessarily outdated in Android, but they are not the recommended approach for performing background tasks in most cases. Instead, thread pools and loaders for background tasks are more suitable in modern design. These newer mechanisms are typically more efficient and flexible than Async tasks and Handlers.
Disadvantages of Async Task, Handlers goes as below. We shall also analyze the root causes of these disadvantages below.
- Multiple async tasks are hard to manage and coordinate in a complex application.
- Async tasks do not have a robust error handling mechanism, leading to potential crashes and unpredictable behavior.
- Async tasks and Handlers can easily cause memory leaks if not properly managed.
- Async tasks and Handlers can lead to performance issues if not used properly, such as blocking the main thread or running too many tasks simultaneously.
- Async tasks and Handlers are not suitable for tasks that require a long-running or ongoing process, as they are designed to be short and self-contained.
- Async tasks and Handlers are not suitable for tasks that require a high level of thread synchronization and coordination.
- Async tasks and Handlers do not support thread pooling, which can lead to resource waste and inefficiency.
- Async tasks and Handlers are not suitable for tasks that require a high level of concurrency.By design, one task will run one at a time.
- Handlers do not have a built-in mechanism for error handling, leading to potential crashes and unpredictable behavior.
The Tussle of Parallelism and Concurrency. Surely, Concurrency is the Winner, "suspension" was his warrior
Kotlin coroutines provide a more efficient and flexible approach to concurrency compared to parallelism. In parallelism, multiple tasks are executed simultaneously on separate threads, which can lead to resource waste and potential performance issues. In contrast, coroutines allow multiple tasks to be executed concurrently on a single thread. Coroutines use a lightweight and non-blocking mechanism. The icing on the cake, is that, in Kotlin Coroutines, the execution of code is suspended which means that whenever a thread is delayed, the thread is made to work on the other tasks. This allows for efficient resource utilization and improved performance. And guess what, by estimations, Kotlin Coroutines can turn the tables by about ~10,000 times more efficiency than the regular thread executions.
Additionally, coroutines support advanced features such as thread pooling, cancellation, and error handling, which enable a higher level of control and flexibility in managing concurrent tasks. On the other hand, Async tasks with parallelism rely on the Android OS for the scheduling and execution which make them dependent and slower.
A small demonstration on how we migrated these Async Tasks
Step 1: Understanding of Async Tasks
To initialise an AsyncTask
, we need to create a new class that extends the AsyncTask
class and overrides the doInBackground()
method. This method will contain the code for the background task that needs to be executed. One of the classic examples for this in our App was the user Login Module where a network authentication is needed depending on whether a user is already logged in or not.
For example, consider a scenario where we need to perform a network request and update the UI with the response. We can create an AsyncTask
as follows:
Step 2: Execution of Async Tasks
To execute the AsyncTask
, we can call the execute()
method, passing in any required parameters. For example:
This will execute the network request in the background and update the UI with the response when the task is completed. The same logic that is comprising the doInBackground()
will be transferred to the suspend function in the Coroutine Approach.
Step 3:Initializing the Suspend Function
We can convert this AsyncTask
to a suspending
function as follows:
Step 4:
To execute the task, we can use the appropriate coroutine builder, such as launch()
or async()
. For example
This will execute the network request in a new coroutine and update the UI with the response when the task is completed.
Comparison of Async Task and Handlers with Kotlin Coroutines
This is a comprehensive comparison of AsyncTask, Handler with Thread Management, and Kotlin coroutines. The "Ease of use" and "Code complexity" points reflect my own subjective assessment of these approaches based on their overall learning curve and the level of complexity involved in implementing and using them effectively. These are the comparative factors that can be considered to list out the pros and cons of the two tools.
Conclusion:
In conclusion, Kotlin Coroutines provide several advantages over Async Task and Handlers, including better performance, more fine-grained control over Thread management, support for lifecycle management, and advanced mechanisms for thread synchronisation. These features make Kotlin Coroutines better suited for a range of tasks, including long-running and high-concurrency tasks, and help prevent common issues such as performance bottlenecks and memory leaks. Therefore, Kotlin Coroutines are a better choice than Async Task and Handlers for most Android applications.
Join us
Scalability, reliability and maintainability are the three pillars that govern what we build at Halodoc Tech. We are actively looking for engineers at all levels and if solving hard problems with challenging requirements is your forte, please reach out to us with your resumé at careers.india@halodoc.com.
About Halodoc
Halodoc is the number 1 all around Healthcare application in Indonesia. Our mission is to simplify and bring quality healthcare across Indonesia, from Sabang to Merauke. We connect 20,000+ doctors with patients in need through our Tele-consultation service. We partner with 3500+ pharmacies in 100+ cities to bring medicine to your doorstep. We've also partnered with Indonesia's largest lab provider to provide lab home services, and to top it off we have recently launched a premium appointment service that partners with 500+ hospitals that allow patients to book a doctor appointment inside our application. We are extremely fortunate to be trusted by our investors, such as the Bill & Melinda Gates Foundation, Singtel, UOB Ventures, Allianz, GoJek, Astra, Temasek and many more. We recently closed our Series C round and In total have raised around USD$180 million for our mission. Our team works tirelessly to make sure that we create the best healthcare solution personalised for all of our patient's needs, and are continuously on a path to simplify healthcare for Indonesia.