Coroutines Masterclass: Chapter-1: Foundation of Coroutines.

SUMIT KUMAR
7 min readJul 23, 2023

--

In today’s fast-paced world of software development, the demand for efficient and user-friendly asynchronous programming techniques has never been higher. In response to this need, Kotlin introduces “Coroutines,” a powerful feature that revolutionizes how we handle concurrency and asynchronous tasks.

Welcome to comprehensive guide on Kotlin Coroutines! In this article series, I will take you on a captivating journey, starting from the fundamentals and gradually delving into advanced concepts. So, grab your favorite cup of coffee, get comfortable, and let’s deep dive into the world of Coroutines.

In this first chapter, we will explore the fundamentals and prerequisites required to grasp the concept of coroutines fully. We’ll discuss the significance of coroutines, their unique properties, and how they differ from traditional threads in Android development. You’ll learn how to implement coroutines, utilize the delay() function for time-based pauses, and harness the power of suspend functions for seamless handling of asynchronous tasks. We'll also delve into the runBlocking lambda function and its role in bridging synchronous and asynchronous code. By the end of this chapter, you'll have a strong foundation to dive deeper into the world of coroutines. Happy reading!

TOPICS COVERED IN THIS CHAPTER

  • Need of Coroutines
  • What are coroutines
  • coroutines properties
  • implementation of coroutines
  • delay function
  • suspend function
  • run-blocking lambda function

(Skip topics if already familiar)

Need of Coroutines

In the world of mobile app development, the main thread, also known as the UI thread, serves as the backbone of user interface interactions. It handles tasks like button clicks, UI updates, and user interactions, ensuring a smooth and responsive user experience. However, when faced with time-consuming operations like network requests, database queries, or image loading, the main thread can become overwhelmed, leading to unresponsiveness and dreaded Application Not Responding (ANR) errors.

To overcome these challenges, developers traditionally turned to threads for handling background tasks. While threads offer a way to execute tasks concurrently, managing multiple threads can be resource-intensive and prone to errors due to out-of-memory and several other reasons.

Enter Kotlin Coroutines — a powerful and lightweight solution! Coroutines enable developers to write asynchronous code sequentially and structured, without the complexity of manually managing threads. By leveraging coroutines, developers can efficiently handle background tasks while keeping the main thread responsive, ensuring a seamless user experience.

What are COROUTINES

Coroutines in Kotlin represent a groundbreaking paradigm shift in asynchronous programming. They offer a lightweight and single-threaded solution for managing concurrent tasks more efficiently. Unlike traditional threads, multiple coroutines can be launched independently on a single thread handling different operations, reducing the overhead of managing multiple threads.

Multiple threads, each thread handling one operation
Multiple coroutines on a single thread handling various operations

The key difference between threads and coroutines in this scenario is how they manage concurrent tasks. Threads represent a single kitchen with multiple pans, where each pan cooks one dish at a time, leading to potential delays. On the other hand, coroutines represent multiple cooking stations, enabling you to handle various tasks simultaneously and switch between them seamlessly, resulting in a more efficient cooking process and smoother customer service.

PROPERTIES OF COROUTINES

  1. Lightweight: Coroutines are lightweight compared to traditional threads, allowing for the creation of thousands of coroutines without consuming excessive system resources(very very cheap).
  2. Single Threaded: Coroutines can be launched on a single thread, avoiding the overhead of managing multiple threads and making them more efficient.
  3. Cooperative Multitasking: Coroutines offer cooperative multitasking, allowing tasks to be paused and resumed without blocking the main thread, leading to smoother execution.
  4. Asynchronous Execution: Coroutines enable asynchronous execution of tasks, allowing time-consuming operations to run in the background without affecting the responsiveness of the main thread.
  5. Structured Concurrency: Coroutines follow the principle of structured concurrency, automatically managing their lifecycles and ensuring proper resource cleanup.
  6. Exception Handling: Coroutines provide built-in support for handling exceptions, making error management more straightforward and less error-prone.

Basic Implementation Of Coroutines And Thread

Understanding and observing the difference between the behavior of thread and coroutine.
Firstly, thread is used for concurrency after that same code is executed using coroutines, see the difference below:

using thread
output when thread is used

Observation: Application did wait for background thread launched,even when the last line was executed. Now the same does not happen in case of coroutines.

using coroutines
output when coroutines is used

Observation: The application didn't wait for coroutine launched.

Conclusion: Unlike traditional threads, coroutines in Kotlin, by default, execute asynchronously and do not block the main thread

This means that the application will not wait for coroutines to complete their execution before proceeding with further code. While it’s possible to use Thread.sleep(DURATION) to wait for a specific duration, this method is impractical for handling coroutines, especially when their execution time is unpredictable (e.g., performing I/O or network operations).

In the upcoming sections, we will explore more advanced techniques to handle coroutine execution and synchronization, allowing for efficient and responsive handling of concurrent tasks without unnecessary delays.

Using Thread.sleep(DURATION) within a coroutine is not recommended as it makes the entire thread and other launched coroutines inactive. Instead, Kotlin provides the delay() function for coroutines, which suspends execution without blocking the thread, ensuring a more efficient and non-blocking approach to asynchronous programming.

Delay Function: delay()

The delay() function is a suspend function, that allows for suspending the execution of a coroutine without blocking the underlying thread. It is specifically designed to handle time-based delays and provides a simple and efficient way to introduce pauses within a coroutine.

  1. Non-Blocking: When a coroutine encounters delay(), it suspends its execution without blocking the underlying thread. This allows other coroutines to continue executing and keeps the application responsive.
  2. Time-Based Suspension: The delay() function takes a specified time duration (in milliseconds) as its argument, determining how long the coroutine should suspend before resuming.
  3. Cancellable: Coroutines are cancellable, and the delay() function is no exception. If a coroutine is canceled before the delay() is completed, it will not resume execution, preventing unnecessary work.

Suspend Functions

A suspend function in Kotlin is a special kind of function used with coroutines. It allows us to perform time-consuming tasks like network requests or database operations without blocking the main thread.

  1. Asynchronous Operations: They help perform tasks in the background without slowing down the rest of the code.
  2. Easy to Use: We can use them just like regular functions, but they can pause and resume execution.
  3. No Callbacks: Unlike traditional methods, we don't need complex callbacks to handle results.

Now implementing the same code using delay function:

delay in coroutines and sleep in thread
output for the above code
fun main(args: Array<String>) {
println("Hey program starts here: ${Thread.currentThread().name}")
GlobalScope.launch {
delay(1000)
println("Sumit is working in background thread: ${Thread.currentThread().name}")
}
Thread.sleep(2000)
println("hey program ends here: ${Thread.currentThread().name}")
}

if we try to use delay() in place of Thread.sleep(2000) in the main thread, it will give a compilation error, as delay() is a suspend function and can only be called by coroutines and suspend functions.

This can be solved using runblocking{} + delay() , so next we will see what is run-blocking lambda and its need.

Run-Blocking Lambda Function

runBlocking is a coroutine builder that allows you to create a new coroutine and block the current thread until the coroutine completes its execution. It is mainly used in testing scenarios or in places where you need to bridge the gap between asynchronous and synchronous code.

The runBlocking coroutine builder takes a lambda function as its argument. The lambda function contains the code that will be executed as part of the coroutine. Inside the runBlocking block, you can launch other coroutines, use delay(), or call other suspend functions.

Working of runBlocking:

  1. When the runBlocking block is encountered, it creates a new coroutine context for the lambda function.
  2. The current thread is blocked, meaning that it will wait until all the code inside the runBlocking block, including launched coroutines, completes.
  3. The coroutine inside the runBlocking block runs synchronously, and the code execution continues line by line.
  4. If the lambda function inside runBlocking contains a delay() or other suspending functions, the coroutine will pause at those points, but the thread will still be blocked.
run-blocking is used
output when runblocking is used
fun main(args: Array<String>) = runBlocking {
println("Hey program starts here: ${Thread.currentThread().name}")
GlobalScope.launch {
delay(1000)
println("Sumit is working in background thread: ${Thread.currentThread().name}")
}
delay(2000)
println("hey program ends here: ${Thread.currentThread().name}")
}

Thank you for reading! I hope you enjoyed the article and found it valuable in enhancing your knowledge. This was just the beginning(chapter-1), and there’s much more to explore in the upcoming chapters of the series. Stay tuned for high-quality articles that will further enrich your understanding. If you have any further questions or would like to contribute to the discussion, please feel free to leave your comments below. Your feedback and engagement are greatly appreciated. Thank you once again, and happy coding!

INIT KOTLIN : )

Coroutines Masterclass :

Chapter-2(coroutines builders)

Chapter-3(coroutines cancellation and exception handling.)

Chapter-4( coming soon)

Chapter-5( coming soon)

--

--

SUMIT KUMAR
SUMIT KUMAR

Written by SUMIT KUMAR

SDE(Android) || Ex-Ingenium || Modern Mobile Developer📱

Responses (4)