Table of contents
In this article, I’ll explain what a Coroutine is, where it fits our programming requirements, and how it behaves internally for our machine.
Note: This article doesn’t explain the Internal workings of a Coroutine, If you already know what a coroutine is, skip this article and jump to “How Suspend Functions Work in Kotlin”.
To understand the coroutine, you should be familiar with Threads and how they work in Processes. I will start things from the basics so you can understand the exact use and need of Coroutines.
How do things work?
Suppose you have any App(.apk/.exe), which, in technical terms is called a Program.
For example, a firefox.exe is a program(executable file) that contains code or a set of instructions stored as a file on your disk.
When you run the app, the code in the program is loaded into the memory/RAM and executed by the processor, and it becomes a process.
An active process also includes the resources(Registers, Stack Pointers, etc) the program needs to run.
A thread is the unit of execution within the process. A process has at least one thread, which is called the main thread. It is not uncommon for a process to have many threads. Each thread has its own stack, registers, etc, so it’s better to say a Thread takes all the resources and not a Process.
Process vs Thread video by ByteByteGo
The operating system runs the thread or process on the CPU by context switching. Context switching is expensive because it involves saving and loading registers, switching out memory pages, and updating various kernel data structures. Switching execution between threads also requires context switching.
Coroutines are on the rescue… to reduce your context-switching costs.
We will need Coroutines to make our Network calls, Database calls, and perform Complex /Time-consuming calculations all while not disturbing the actual flow of our application(Main Thread).
Threads were doing it fine, but we need to Optimize our app's performance and save resources as much as possible, and Coroutines are so lightweight that you can have 100s of them running in your app.
Now that you know why coroutines are required, let’s understand what a coroutine is.
Coroutine, What?
According to Kotlinlang: A coroutine is an instance of a suspendable computation.
You got it? Nah? Let’s understand:
It consists of two words: Co, which means cooperative, and Routines, which means Functions/Operations.
So, they are basically super-powered functions that pause the execution whenever their a heavy operation to do and continue the execution when the heavy operation is done.
The Heavy operation like what?
suspend fun getData(uid: String){
val apiUrl = "SomeUrl/$uid"
updateLoadingState()
val response = getDataFromApiCall(apiUrl)//Heavy Operation like api call
updateUIState(response)
}
This suspend function will work only inside a coroutine.
Note: Must read “How Suspend Functions Work in Kotlin” after this article, to get clarity on Internal workings of Coroutine in Kotlin.
The coroutine will work like a normal function at first,
It will execute the first line, build the apiUrl, and then update the loading state in the second line.
The third line is a suspend function getDataFromApiCall, it will call this function and pause the execution.
It will wait until the function returns something.
Once the function gives the response, it continues the execution and executes the last line.
So, Coroutines are pausable operations/functions(suspend function is not a coroutine) that run on a Thread.
Coroutines are considered light-weight threads, in the sense that it takes a block of code to run that works concurrently with the rest of the code.
Using and creating a Coroutine is more powerful than compared to a Thread for many reasons:
They are executed within a thread
Coroutines are suspendable(Pause and Resume)
They can switch contexts/Threads.
How to Use?
Every Coroutine need a to be started in a scope, which is called a CoroutineScope.
For starting a Coroutine, we need a Coroutine Builder, which will actually build us an “Instance of suspendable computation”.
For creating a Global scope which lives for your whole app’s life, you can use:
GlobalScope.launch {
print("Hello coroutine from ${Thread.currentThread().name}")
}
print("Hello main ${Thread.currentThread().name}")
//Output:
Hello main main
Hello coroutine from DefaultDispatched-worker-1
Hence proved, they are not working on the same thread. You can also try to minmic the suspend(using delay()) of this coroutine and check that it will resume in a different thread.
GlobalScope.launch {
print("Hello coroutine from 1 ${Thread.currentThread().name}")
delay(100L)
print("Hello coroutine from 2 ${Thread.currentThread().name}")
}
print("Hello main ${Thread.currentThread().name}")
//Output:
Hello main main
Hello coroutine from 1 DefaultDispatched-worker-1
Hello coroutine from 2 DefaultDispatched-worker-2 // May differ for you.
Generally, it is not required to use GlobalScope and you will be using the “viewmodelScope” in most usecases.
This article was for a beginner to understand the requirement, position and use of Coroutine. I hope the purpose is served here.
If you want to understand the Internal working, then jump to How Suspend Functions Work in Kotlin.
In my next article, I’ll be sharing all the things you need to know Kotlin coroutine as a Pro Kotlin Developer.
Make sure to Follow me and Subscribe to Email and get notified for updates.