Androdi kotlin Coroutines(协程)详解 (一)
Androdi kotlin Coroutines(协程)详解 (二)
Androdi kotlin Coroutines(协程)详解 (三)
Androdi kotlin Coroutines(协程)详解 (四)
Androdi kotlin Coroutines(协程)详解 (五)
Androdi kotlin Coroutines(协程)详解 (六)
二、协程的启动
build.gradle 引入协程库
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" //协程核心库
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" //Android协程扩展库
2.1 启动方法
2.1.1 GlobalScope启动
GlobalScope.launch {
//to do some thing
}
GlobalScope 实现了接口 CoroutineScope ,而 CoroutineScope 有 launch 方法,不阻塞线程
相关的源码如下:
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block)
else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
比如下面的代码:
fun startCoroutineByGlobeScope() {
println("start execute ${Thread.currentThread().name}")
GlobalScope.launch {
println("launch start execute ${Thread.currentThread().name}")
delay(1000)
println("launch end execute ${Thread.currentThread().name}")
}
println("end execute ${Thread.currentThread().name}")
Thread.sleep(2000)
}
运行结果:
start execute main
end execute main
launch start execute DefaultDispatcher-worker-1 @coroutine#1
launch end execute DefaultDispatcher-worker-1 @coroutine#1
Job
后台的工作。从概念上讲,作业是一种可取消的东西,它的生命周期最终将完成。Job 可以取消并且有简单生命周期,它有三种状态:
State | [isActive] | [isCompleted] | [isCancelled] |
---|---|---|---|
New (optional initial state) | false | false | false |
Active (default initial state) | true | false | false |
Completing (optional transient state) | true | false | false |
Cancelling (optional transient state) | false | false | true |
Cancelled (final state) | false | true | true |
Completed (final state) | false | true | false |
//Job中的方法
job.isActive //是否存活
job.isCancelled //是否关闭
job.isCompleted //是否完成
job.cancel() //关闭
job.join() //挂起协程直到执行完毕
job.start() //开始执行
2.1.2 CoroutineScope启动
CoroutineScope(context = EmptyCoroutineContext).launch {
// to do something
}
2.1.3 runBlocking {}启动
runBlocking {}是创建一个新的协程同时阻塞当前线程,直到协程结束。这个不应该在协程中使用,主要是为main函数和测试设计的。
private fun runBlockingCoroutine() {
println("runBlockingCoroutine start work thread ${Thread.currentThread().name}")
runBlocking {
delay(1000)
println("runBlockingCoroutine ${Thread.currentThread().name}")
}
println("runBlocking end work thread ${Thread.currentThread().name}")
}
2.1.4 实现CoroutineScope接口,初始化上下文
如GlobalScope 是 CoroutineScope 的一个单例实现
2.2 四种启动方式 CoroutineStart
public enum class CoroutineStart {
DEFAULT,
LAZY,
@ExperimentalCoroutinesApi
ATOMIC,
@ExperimentalCoroutinesApi
UNDISPATCHED;
}
模式 | 功能 |
---|---|
DEFAULT | 立即执行协程体 |
LAZY | 懒汉式,只有在需要的情况下运行 |
ATOMIC | 立即执行协程体,但在开始运行之前无法取消,实验api |
UNDISPATCHED | 立即在当前线程执行协程体,直到第一个 suspend 调用,实验api |
2.2.1 DEFAULT
DEFAULT 是饿汉式启动, launch 调用后,会立即进入待调度状态,一旦调度器 OK 就可以开始执行。
示例:
Log.d(TAG, " oncreate start")
GlobalScope.launch(start = CoroutineStart.DEFAULT) {
Log.d(TAG, "block start")
for (i in 1..5) {
Log.d(TAG, "num is $i")
delay(500)
}
Log.d(TAG, "block end")
}
Log.d(TAG, " oncreate end")
运行结果:
D/TestActivity: oncreate start
D/TestActivity: oncreate end
D/TestActivity: block start
D/TestActivity: num is 1
D/TestActivity: num is 2
D/TestActivity: num is 3
D/TestActivity: num is 4
D/TestActivity: num is 5
D/TestActivity: block end
2.2.2 LAZY
LAZY 是懒汉式启动, launch 后并不会有任何调度行为,协程体也自然不会进入执行状态,直到我们需要它执行的时候。这其实就有点儿费解了,什么叫我们需要它执行的时候呢?就是需要它的运行结果的时候, launch 调用后会返回一个 Job 实例,对于这种情况,我们可以:
- 调用 Job.start ,主动触发协程的调度执行
- 调用 Job.join ,隐式的触发协程的调度执行
Log.d(TAG, " oncreate start")
val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
Log.d(TAG, "block start")
for (i in 1..5) {
Log.d(TAG, "num is $i")
delay(500)
}
Log.d(TAG, "block end")
}
job.start()
Log.d(TAG, " oncreate end")
2.2.3 ATOMIC
ATOMIC 只有涉及 cancel 的时候才有意义,在这里我们就简单认为 cancel 后协程会被取消掉,也就是不再执行了。那么调用cancel 的时机不同,结果也是有差异的,例如协程调度之前、开始调度但尚未执行、已经开始执行、执行完毕等等。
Log.d(TAG, " oncreate start")
val job = GlobalScope.launch(start = CoroutineStart.ATOMIC) {
Log.d(TAG, "block start")
for (i in 1..5) {
Log.d(TAG, "num is $i")
delay(500)
}
Log.d(TAG, "block end")
}
job.cancel()
Log.d(TAG, " oncreate end")
2.2.4 UNDISPATCHED
协程在这种模式下会直接开始在当前线程下执行,直到第一个挂起点,这听起来有点儿像前面的 ATOMIC ,不同之处在于UNDISPATCHED 不经过任何调度器即开始执行协程体。当然遇到挂起点之后的执行就取决于挂起点本身的逻辑以及上下文当中的调度器了。
Log.d(TAG, " oncreate start")
val job = GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {
Log.d(TAG, "block start")
for (i in 1..5) {
Log.d(TAG, "num is $i")
delay(500)
}
Log.d(TAG, "block end")
}
Log.d(TAG, " oncreate job.start")
job.start()
Log.d(TAG, " oncreate end")