协程的作用域构建器
RunBlocking
runBlocking是常规函数,会把当前主线程包装成一个主协程,其会阻塞当前线程, 只有当等待其主协程体以及里面的所有子协程执行结束以后,才会让当前线程执行,
CoroutineScope
coroutineScope是挂起函数,不会阻塞当前线程。
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {}
public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R {}
CoroutineScope与SupervisorScope的区别:
coroutineScope 一个协程执行失败了,所有其他兄弟协程执行就会中断 (一毁俱毁)
supervisorScope 一个协程执行失败了,不会影响其他兄弟协程的执行 (一毁不俱毁)
private fun coroutineScopeTest() {
// coroutineScope 一个协程执行失败了,所有其他兄弟协程执行就会中断 (一毁俱毁)
runBlocking {
coroutineScope {
launch {
delay(400)
LogUtil.e("job1 was executed.")
}
launch {
delay(200)
LogUtil.e("job2 was executed.")
throw IllegalArgumentException()
}
}
}
//只会输出 job2 was executed. 协程1 中断了 不会输出结果
}
private fun supervisorScopeTest() {
// supervisorScope 一个协程执行失败了,不会影响其他兄弟协程的执行 (一毁不俱毁)
runBlocking {
supervisorScope {
launch {
delay(400)
LogUtil.e("job1 was executed.")
}
launch {
delay(200)
LogUtil.e("job2 was executed.")
throw IllegalArgumentException()
}
}
}
//会输出 job2 was executed. job1 was executed.
}
Launch
launch 返回一个Job类型,并且不附带任何结果值,没有返回结果值
如果你要在launch函数里执行逻辑,会执行里面的逻辑,但是没有任何返回结果值的(如果你想要有返回结果值 使用Async)
public fun CoroutineScope.launch():Job
返回Job类型有个join()函数,是个协程方法,不会阻塞线程。调用此函数意识是 要等当前调用此函数 的协程执行完逻辑后,才会执行其他的子协程
public interface Job : CoroutineContext.Element {
public suspend fun join()
}
Async
async返回Deferred类型(集成Job类型 ),(注意我们返回Deferred类型不是我们最总需要的返回结果值) 需要调用await()方法返回我们最终需要的结果值
public fun <T> CoroutineScope.async(): Deferred<T>
返回类型Deferred<T>有个await()函数,是个协程方法,不会阻塞线程。调用此函数意识是 要等当前调用此函数 的协程执行完逻辑后,才会执行其他的子协程,同时其还会返回该子协程执行的逻辑结果值
public interface Deferred<out T> : Job {
public suspend fun await(): T
}
runBlocking {
val job1: Job = launch {
delay(500)
LogUtil.e("job1 was executed.") //执行了launch里的 逻辑: 输出 job1 was executed
"方明飞"
}
LogUtil.e(job1.toString() ) //没有返回结果值 StandaloneCoroutine{Active}@b57027
job1.join() //什么意识了? 要等子协程job1执行完后,才会执行后面的子协程job2 job3
val job2 :Deferred<String> =async {
delay(250)
LogUtil.e("job2 was executed.") //执行了launch里的 逻辑: 输出 job2 was executed.
val normalData12:NormalData =get<NormalData>(named("userNameAge"))
normalData12.userName
}
LogUtil.e("${job2.toString()}") //输出 DeferredCoroutine{Active}@a96d2d4
val job2Result:String = job2.await()//什么意识了? 要等子协程job2执行完后,才会执行后面的子协程 job3
LogUtil.e(job2Result)//输出结果值 方明飞
val job3 :Deferred<Int> =async {
delay(100)
LogUtil.e("job3 was executed.") //执行了launch里的 逻辑: 输出 job3 was executed.
val normalData122:NormalData =get<NormalData>(named("userNameAge"))
normalData122.age
}
job3.await()//什么意识了?要等子协程job3执行完后,才会执行主线程
LogUtil.e("${job3.await()}")//输出结果值 34
LogUtil.e("${job3.toString()}") //输出 DeferredCoroutine{Completed}@a6c8c7d
}
协程启动模式CoroutineStart
协程的启动模式是指定协程启动后的一些行为
public enum class CoroutineStart {
DEFAULT,
LAZY,
ATOMIC,
UNDISPATCHED;
}
DEFAULT 创建协程后,立即开始调度执行。 饿汉式启动 launch 调用后,会立即进入待调度状态。 在调度前如果协程被取消,其将直接进入取消状态。
LAZY 只有在需要的情况下运行。 是懒汉式启动 launch 后并不会有任何调度行为,协程体也自然不会进入执行状态, 直到我们需要它执行的时候。
那什么时候我们需要它执行的时候呢?
launch 调用后会返回一个 Job 实例,
调用 job.start(),主动触发协程的调度执行,
调用 job.join(),隐式的触发协程的调度执行
asynic 调用后返回一个Deferred<out T>
调用 Job.await(),才会开始执行调度.
ATOMIC 协程创建后,立即开始调度执行,但在开始运行之前无法取消
UNDISPATCHED 立即在当前线程执行协程体,直到第一个 suspend 调用
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {}
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> {}
Job对象和生命周期
对于每一个新创建的协程(通过launch或者async),会返回一个Job实例,该Job实例是协程的唯一标示,并且负责管理协程的生命周期。
Job的生命周期
一个协程任务可以包含一系列Job的生命周期状态:
新创建(New)、活跃(Active)、完成中(Completing)、已完成(Completed)、取消中(Cancelling)和已取消(Cancelled)。
虽然我们无法直接访问这些状态,但是我们可以访问Job的属性:isActive、isCancelled和isCompleted。
如果协程处于活跃状态,协程运行出错或者调用 job.cancel() 都会将当前任务置为取消中 (Cancelling) 状态 (isActive = false, isCancelled = true)。
当所有的子协程都完成后,协程会进入已取消 (Cancelled) 状态,此时 isCompleted = true