-
Notifications
You must be signed in to change notification settings - Fork 22
What is Coroutine and How it works
Devrath edited this page Feb 5, 2024
·
8 revisions
- 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.
- 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 andpart 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 assub-routine
. So asub 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
- 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.
- 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
- 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 likejob
anddispatcher
, since noting is specified we mentionEmptyCoroutineContext
. 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.
-
- 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.
- The
co-routine builder
is like abridge
betweensuspending
andnon-suspending
functions. - Co-routine builder can run suspending functions.
- Co-routine build can run normal functions.
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
-
launch:
- Used for starting a new coroutine without returning any result.
CoroutineScope(Dispatchers.Main).launch { // Coroutine code }
-
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 }
- Used for starting a coroutine that computes a result. It returns a
-
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 }
-
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 }