- 
                Notifications
    You must be signed in to change notification settings 
- Fork 24
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-AinvokesjoinonJob-Bthe 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-stateintoactive-stateby default.
- If you have started the co-routine by LAZYthen you need to invokestart()orjoin()to make the job go fromnew-stateintoactive-state.
- A running co-routine is always in active-state. At any point, a running co-routine can becanceledorcompleted.
- 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 exceptioncauses 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 blockedinstead 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
         */
}