Skip to content

What is Coroutine and How it works

Devrath edited this page Feb 5, 2024 · 8 revisions

What is coroutine

  • Co-routines allow functions to yield control, Meaning functions can co-operate
  • Co-routines can be suspended and re-run from that point at a later stage. The Important thing to observe here is that we will not rely on threading to achieve this.
  • Co-routines provide the context in suspend functions that can be run. When the suspend function is run, We need some extra information and that extra information is provided by the co-routine.
  • The context is created when we create a coroutine builder.

How co-routine works

  • Every time you launch the process -> In our scenario launching the application. Android OS creates something called main routine
  • In a program we call also as main function -> This main function is the entry part of your program and part of the main routine
  • Now the program gets bigger and bigger and so does the number of functions and number of calls to other functions.
  • Now say you call another function from the main-routine we call it as sub-routine. So a sub routine is just another routine nested in a routine
  • The Android OS stack all these routines in a stack, A construct that keeps track of what’s currently running and how the current routine has been called. when the subroutine is finished, that routine is popped off the stack and the control is passed back to the routine that is called that stack -> finally if the stack is empty and there are no more routines the program finishes
  • A subroutine is a blocking call and a coroutine is a non-blocking call. so a nonblocking call saying coroutine can run in parallel
fun main() {
  (1..50000).forEach { // - This will launch a loop of 50,000 coroutines
    GlobalScope.launch { // - This will launch a coroutine
      val threadName = Thread.currentThread().name 
      println("$it printed on thread ${threadName}")
    }
  }
  Thread.sleep(1000) // ---> This is to keep the program main thread waiting until all co-routines are completed
}
  • If same above we launch in a thread, like 50,000 threads one after another in a loop, the program will crash from out-of-memory error.
  • But using a co-routine still we are able to run easily
  • This is because coroutines manage the existing threads instead of creating a new one

Why do we need the coroutine scope

  • We need the coroutine scope to launch coroutines because the coroutines are just background mechanisms that don't care about the life cycle of the starting point
  • Now suppose we close the application before the coroutine completes without scope we will not have to control of the coroutines that we launch in the background.

What is meant by launching a coroutine

  • We need a coroutine builder to launch a coroutine.
  • The coroutine library has several coroutine builders that are used to launch a coroutine.
public fun CoroutineScope.launch(
  context: CoroutineContext = EmptyCoroutineContext,
  start: CoroutineStart = CoroutineStart.DEFAULT,
  block: suspend CoroutineScope.() -> Unit
): Job

0_zfczumO5AsG80pyj

  • The first two parameters are optional.
  • The third one needs a suspend function which is compulsory.
    • CoroutineContext-> It is the contextual dataset information about the current coroutine, This can contain information like job and dispatcher, since noting is specified we mention EmptyCoroutineContext. So whatever the context the coroutine specifies the current coroutine uses it.
    • CoroutineStart-> It is the mode in which the coroutine starts
      • DEFAULT -> It schedules the coroutine for the execution based on the context it is passed.
      • LAZY -> Starts the coroutine lazily.
      • ATOMIC -> It is the same as default but it cannot be canceled before it starts.
      • UNDISPATCHED -> Runs the coroutine until the first suspension point.
    • suspend CoroutineScope.()-> It is a lambda where we need to pass the code that we want to execute and it's suspended because we can nest multiple coroutines in as children.

Why the coroutine scope was created

  • Actually in earlier versions of coroutine API's, There were problems like, Say the main coroutine finishes the child coroutines might not have finished, and used to create a lot of problems in handling them.
  • So the coroutine APIs were improved to have the context of the previous lifecycle of a parent using coroutine context.

What is co-routine builder

1b28e3fcf85cc79b1c23f434479b86c3-ht

  • The co-routine builder is like a bridge between suspending and non-suspending functions.
  • Co-routine builder can run suspending functions.
  • Co-routine build can run normal functions.

Different co-routine builders

There are several coroutine builders provided by the Kotlin Coroutine library that you can use in Android development. Here are some of the most commonly used coroutine builders:

  • launch
  • async
  • runBlocking
  • withContext
  1. launch:

    • Used for starting a new coroutine without returning any result.
    CoroutineScope(Dispatchers.Main).launch {
        // Coroutine code
    }
  2. async:

    • Used for starting a coroutine that computes a result. It returns a Deferred object that can be used to obtain the result.
    val deferredResult: Deferred<ResultType> = CoroutineScope(Dispatchers.IO).async {
        // Coroutine code with a result
        return@async result
    }
  3. runBlocking:

    • Used to start a coroutine from a non-suspending context. It blocks the current thread until the coroutine inside it completes.
    runBlocking {
        // Coroutine code
    }
  4. withContext:

    • Used for changing the coroutine context during its execution. It is often used to switch between different dispatchers.
    withContext(Dispatchers.IO) {
        // Coroutine code in a different dispatcher
    }
Clone this wiki locally