Job and Its Lifecycle

Job States

New ──start──► Active ──body done──► Completing ──children done──► Completed
                  │                         │
                  └──cancel / fail──► Cancelling ──children done──► Cancelled
StateisActiveisCompletedisCancelled
New (lazy, not started)falsefalsefalse
Activetruefalsefalse
Completingtruefalsefalse
Cancellingfalsefalsetrue
Cancelledfalsetruetrue
Completedfalsetruefalse

Watching a Job

Example

invokeOnCompletion runs a callback when the job ends (normally or by cancellation).

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch(start = CoroutineStart.LAZY) { delay(100) }
    println("Lazy:      active=${job.isActive} completed=${job.isCompleted}")
    job.start()
    println("Started:   active=${job.isActive} completed=${job.isCompleted}")
    job.invokeOnCompletion { cause -> println("Completion callback, cause=${cause?.javaClass?.simpleName}") }
    job.join()
    println("Joined:    active=${job.isActive} completed=${job.isCompleted} cancelled=${job.isCancelled}")

    val job2 = launch { delay(1000) }
    delay(10)
    job2.cancel()
    println("Cancelling: active=${job2.isActive} cancelled=${job2.isCancelled}")
    job2.join()
    println("Cancelled:  completed=${job2.isCompleted} cancelled=${job2.isCancelled}")
}

Output

Lazy:      active=false completed=false
Started:   active=true completed=false
Completion callback, cause=null
Joined:    active=false completed=true cancelled=false
Cancelling: active=false cancelled=true
Cancelled:  completed=true cancelled=true

Useful Job Functions

FunctionWhat it does
join()suspend until the job finishes
cancel()request cancellation (does not wait)
cancelAndJoin()cancel and wait until it really stopped
childrensequence of child jobs
cancelChildren()cancel children but keep the job itself active
invokeOnCompletion { }callback when finished