-
Notifications
You must be signed in to change notification settings - Fork 23
How Job in coroutine works
Devrath edited this page Jan 15, 2024
·
16 revisions
- A coroutine returns a Job
- Using the Job we can create control the coroutine like stopping it, So a Job on a coroutine is a handle to the coroutine.
- More flexibility can be achieved using jobs, we can combine the instances of jobs using
join()
. - Say
Job-A
invokesjoin
onJob-B
the former won't be executed until later has finished on execution. - We can also set up a parent and child relation using which we can ensure parent won't complete until the child has completed its execution.
-
New-State
:-> When you launch a co-routine, you can create a job, It returns a new state. -
Active-State
:->- Once the coroutine is started the job goes from
new-state
intoactive-state
by default. - If you have started the co-routine by
LAZY
then you need to invokestart()
orjoin()
to make the job go fromnew-state
intoactive-state
. - A running co-routine is always in
active-state
. At any point, a running co-routine can becanceled
orcompleted
. - We can check if a job is in
active-state
. - We can also check by looping the Job to check its children and do something for a particular state of the child.
- Once the coroutine is started the job goes from
-
Cancelling-State
:->- Once you launch a coroutine, many things can possibly happen
- Exception might occur
- Because of some new condition, We might need to cancel the job.
- Usually the
uncaught exception
causes the entire program to crash, but since the coroutines have suspending behavior, the exception can also be suspended and handled or managed later - We can cancel a job by calling
cancel()
on the job's reference, The job along with all its children's jobs are also canceled. - If a Job has a parent and the job is canceled, The parent job is also canceled.
- Once you launch a coroutine, many things can possibly happen
* The `supervisor job` is a special job, where we don't need all the children's jobs to complete for a parent job to complete.
* If we have certain conditions of our own for checking the child scope of the job, We should append it with `isActive()` just to be on the safer side.
- Using the delay function inside the coroutine we can make the coroutine wait for a certain amount of time.
- Delay is much different because the thread is
not blocked
instead it's justsuspended
. - Meaning a coroutine that is suspended with delay can be canceled.
- Using the retry mechanism we can loop the code inside the coroutine context a certain number of times mentioned as input.
- This is helpful in writing complex
retry()
mechanism sometimes useful in when writing network request.
private fun retryDemo(){
GlobalScope.launch {
repeat(3){
delay(200)
println("Execution happened")
}
}
/** Output:
* Execution happened
* Execution happened
* Execution happened
*/
}
Here there is dependency in job instances
private fun simpleJobDemo() {
/**
* This since executed by Lazy, It will start only when invoked
*/
val job1 = GlobalScope.launch(start=CoroutineStart.LAZY) {
delay(200)
println("Two")
delay(200)
}
GlobalScope.launch {
delay(200)
println("One")
// Job is invoked here so it is executed here
job1.join()
println("Three")
}
/** OUTPUT:
*
* One
* Two
* Three
*/
}
Passing parent job to the coroutine context, Here There is a parent-child hierarchy. We can clearly see that parent job has the children in it
private fun simpleJobTwoDemo() {
val rootJob = GlobalScope.launch(start = CoroutineStart.DEFAULT){
val parentJob = launch {
delay(10)
println("Parent job started")
delay(10)
}
val childOneJob = launch(context = parentJob) {
delay(10)
println("Child one job started")
delay(10)
}
val childTwoJob = launch(context = parentJob) {
delay(10)
println("Child two job started")
delay(10)
}
if(parentJob.children.iterator().hasNext()){
val childCnt = parentJob.children
println("Parent has $childCnt children")
}else{
println("Parent has no children")
}
Thread.sleep(1000)
}
/**
* OUTPUT:->
* Parent has kotlin.sequences.SequencesKt__SequenceBuilderKt$sequence$$inlined$Sequence$1@85caa11 children
* Parent job started
* Child two job started
* Child one job started
*/
}
Without passing parent job to the coroutine context
private fun simpleJobTwoDemo() {
val rootJob = GlobalScope.launch(start = CoroutineStart.DEFAULT){
val parentJob = launch {
delay(10)
println("Parent job started")
delay(10)
}
val childOneJob = launch() {
delay(10)
println("Child one job started")
delay(10)
}
val childTwoJob = launch() {
delay(10)
println("Child two job started")
delay(10)
}
if(parentJob.children.iterator().hasNext()){
val childCnt = parentJob.children
println("Parent has $childCnt children")
}else{
println("Parent has no children")
}
Thread.sleep(1000)
}
/**
* OUTPUT:->
* Parent has no children
* Parent job started
* Child two job started
* Child one job started
*/
}