未完待续。。
Job
是标准库中启动协程后返回的对象,代表着协程本次作业。我们可以判断协程是否结束,是否取消,是否完成并且可以取消当前协程以及嵌套子协程。
我们简单的看下面的代码如何获取job
对象
fun main() {
val job = GlobalScope.launch {
}
//协程是否存活
job.isActive
//是否取消
job.isCancelled
//是否完成
job.isCompleted
//取消协程
job.cancel()
//(非懒启动模式的)启动协程
job.start()
}
Job继承关系
我们直接首先看类继承关系:
首先我们注意一点:他继承Element
证明他能被放入协程上下文中,且Key
为Job。在标准库启动协程后Job
对象将放入其上下文中
我们看先一个简单的示例代码:
fun log(msg: String) {
println("[${Thread.currentThread().name}] ${msg}")
}
fun main() {
val job = GlobalScope.launch {
//获取当前的上下文
val job = coroutineContext[Job]
log("协程内部job:$job")
}
//协程返回的job和内部或者是同一对象
log("协程外部的job:$job")
TimeUnit.HOURS.sleep(1)
}
输出:
[main] 协程外部的job:StandaloneCoroutine{Active}@63753b6d
[DefaultDispatcher-worker-1] 协程内部job:StandaloneCoroutine{Active}@63753b6d
Job 状态
Job
有三个暴露的函数用于判断其状态:
- isActive 当前协程是否存活(创建协程并没有启动协程的时候返回false)
- isCompleted 当前协程是否完成
- isCancelle 当前协程是否取消
Demo说明:
fun main() {
//启动一个懒启动 CoroutineStart.LAZY用说明isActive不一定
val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
//获取当前的上下文
TimeUnit.MILLISECONDS.sleep(500)
log("协程完成")
}
log("未启动协程之前的状态: isActive: [${job.isActive}] isCompleted: [${job.isCompleted}] isCancelled: [${job.isCancelled}] ")
job.start()
log("启动协程之后的状态: isActive: [${job.isActive}] isCompleted: [${job.isCompleted}] isCancelled: [${job.isCancelled}] ")
TimeUnit.MILLISECONDS.sleep(500)
log("启动协程完成之后的状态: isActive: [${job.isActive}] isCompleted: [${job.isCompleted}] isCancelled: [${job.isCancelled}] ")
TimeUnit.HOURS.sleep(1)
}
输出:
[main] 未启动协程之前的状态: isActive: [false] isCompleted: [false] isCancelled: [false]
[main] 启动协程之后的状态: isActive: [true] isCompleted: [false] isCancelled: [false]
[DefaultDispatcher-worker-1] 协程完成
[main] 启动协程完成之后的状态: isActive: [true] isCompleted: [false] isCancelled: [false]
取消状态Demo:
suspend fun main() {
//启动一个懒启动 CoroutineStart.LAZY用说明isActive不一定
val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
//获取当前的上下文
TimeUnit.MILLISECONDS.sleep(500)
log("协程完成")
}
log("未启动协程之前的状态: isActive: [${job.isActive}] isCompleted: [${job.isCompleted}] isCancelled: [${job.isCancelled}] ")
job.start()
log("启动协程之后的状态: isActive: [${job.isActive}] isCompleted: [${job.isCompleted}] isCancelled: [${job.isCancelled}] ")
job.cancel()
log("启动协程取消之后的状态: isActive: [${job.isActive}] isCompleted: [${job.isCompleted}] isCancelled: [${job.isCancelled}] ")
job.join()
log("启动协程取消并且之后的状态: isActive: [${job.isActive}] isCompleted: [${job.isCompleted}] isCancelled: [${job.isCancelled}] ")
TimeUnit.HOURS.sleep(1)
}
输出:
[main] 未启动协程之前的状态: isActive: [false] isCompleted: [false] isCancelled: [false]
[main] 启动协程之后的状态: isActive: [true] isCompleted: [false] isCancelled: [false]
[main] 启动协程取消之后的状态: isActive: [false] isCompleted: [false] isCancelled: [true]
[DefaultDispatcher-worker-1] 协程完成
[DefaultDispatcher-worker-1] 启动协程取消并且之后的状态: isActive: [false] isCompleted: [true] isCancelled: [true]
由于暴露的相关Api比较简单这里不再过多说明。
当然Job
有自己内部的状态变化,然后这些内部的变化比较多,然后部分变化也就对应了我们isActive,isCompleted,isCancelled三个状态的数值。
简要的说明下内部的状态变化:
New
当我们创建一个协程并未启动时候就是出于New
状态(使用CoroutineStart.LAZY
方式时便可看到).
Active
当我们调用job.start
函数的之后,且当前job
没有执行完成
Cancelling
当我们调用取消的时候立即进入此状态
Cancelled
最终取消任务完成
Completing
当协程完成的时候需要等候子协程完成的状态
Completed
协程完成
Job
一些常用方法或者属性
isActive
协程是否存活(注意懒启动)isCancelled
协程是否取消isCompleted
协程是否完成cancel()
取消协程start()
启动协程join()
阻塞等候协程完成cancelAndJoin()
取消并等候协程完成invokeOnCompletion( onCancelling: Boolean = false, invokeImmediately: Boolean = true, handler: CompletionHandler)
监听协程的状态回调attachChild(child: ChildJob)
附加一个子协程到当前协程上
单独说下 invokeOnCompletion
函数:
invokeOnCompletion
函数用于监听其完成或者其取消状态,onCancelling
参数用于判断是否监听取消事件否则监听完成事件,
invokeImmediately
参数主要用于监听已经完成协程时是否回调,如果为false 那么如果在添加监听事件时协程已经完成或取消那么将不会回调.
fun main() = runBlocking{
val job = GlobalScope.launch {
}
job.join()
job.invokeOnCompletion(onCancelling = false, invokeImmediately = false) {
log("取消的回调"+it)
}
TimeUnit.SECONDS.sleep(10000)
log("main 结束")
}
上面的例子中:
log("取消的回调"+it)
永不执行