Program -> Process -> Thread of execution
Program start a process which has process id and memory, Process start a thread to execute set of instruction that thread is called Thread of execution.
Single thread can execute instruction sequentially so if any instruction taking more time then we can allot that instruction to another thread and do parallel processing to save time and giving user responsive experience.
When thread is in waiting for the response we can use it to completed another task. Coroutines does that.
Coroutine is a framework over threads/thread pool. It uses threads in a most optimum way
Cooperative routines of thread called coroutines. without creating multiple thread, By using them efficiently we can perform the task using this framework
Main thread - Looper - Message Queue
Coroutine Scope: Decides the lifetime or a boundary of coroutine
Coroutine Context: A Dispatcher: Decides the thread pool to perform the instruction
Looper is keep checking if anything to dispatch from a message queue. Any click event any task that written on main thread that is dispatched by the looper and given to the main thread.
Coroutine has scopes like activity, fragment, view model, global etc.
And contexts are Dispatcher.Main/IO/Default
We can do long running task by starting a normal/worker thread only but there is a limitation of creating thread depends upon system and thread creation takes 2mb of memory also. We can not efficiently use thread pool like coroutines
Coroutine can be started using any scope and with appropriate context.
This coroutine is equivalent to the normal thread creation but coroutine supports suspend functions which uses the thread in a most optimum way
CreateGuestuser() is marked a suspend because the createAPIUser() function is suspend function also. while waiting for the response from network the same thread can read files from the system also. once response received the thread resume the execution.
Yield() is suspend function call so at that point task1() coroutine assign the thread to task2() coroutine and when that task2() coroutine is suspended the thread assign to the task1() coroutine back.
That is why coroutines are called co operative functions because they are communication with each other and use the thread pool wisely
Functions that helps to build coroutines
.Launch{} - Fire and forgot
.launch return the job. using job object we can manage the coroutines by wait, join and cancel features.
Join() function wait for the thread to complete the task and come back then only the subsequent statment are executed
launch{} & join()
It returns 0 always because coroutine found the getFBflollowers() function as suspended so after executing that coroutine move forward to the print statement. then when the getFBFollowers() function is returned the print statment is already executed.
Using Join() function we can wait for the coroutine to come back. it enforce the sequential execution
.Async{} - to get the results
.Async{} returns Deferred object
Deferred<T> where T is the generic return type. a last statment in the async{} block will be return type unlike in .launch{} job is the return type
async{} & await()
as Async return the deffered object of last statement we can call .await() function to wait for the execution. like .join() in launch{} call.
Both works same.
Although both are same when we are expecting results we should go for async because it is ment for that only.
What is the best way to implement it?
async{} or launch{}
Async is better to use to fulfil the above requirement. example is as below
using launch{}
using async{}
Deferred is a subclass of job. Deferred has results unlike job
Fb and insta followers can be fetched simultaneously so we should launch two coroutines for that.
If we cancel the parent job then the child jobs are canceled
We can start multiple coroutines within a coroutine
job hierarchy
By canceling the coroutine doesn't abort the running thread. so in this case we have to check the if(isActive) method so if the coroutine is cancelled from outside then the thread get to know about it.
bit confusing but yes lets keep in mind this scenario
WithContext is like launch and async but it is a blocking scope. execute statements sequentially.
RunBlocking is make sure that all the coroutines defined in it's scope should be completed before the next execution.(I can understand this defination only. no more findings)
Normal coroutine without .join() works like a normal thread. A non-blocking behaviour.
WithContext{}.
Using withContext() it will executed sequentially. A Blocking behaviour
General use case for with context is when we start worker thread for the network response and we want to show that on UI by assigning the result to main thread.
Coroutine are in the scope and that scope is attached to any component so once component is destroy the associated coroutines are also cancelled
Viewmodel scope and lifecyclescope for activity and fragment