Androdi kotlin Coroutines(協(xié)程)詳解 (一)
Androdi kotlin Coroutines(協(xié)程)詳解 (二)
Androdi kotlin Coroutines(協(xié)程)詳解 (三)
Androdi kotlin Coroutines(協(xié)程)詳解 (四)
Androdi kotlin Coroutines(協(xié)程)詳解 (五)
Androdi kotlin Coroutines(協(xié)程)詳解 (六)
二、協(xié)程的啟動
build.gradle 引入?yún)f(xié)程庫
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" //協(xié)程核心庫
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" //Android協(xié)程擴(kuò)展庫
2.1 啟動方法
2.1.1 GlobalScope啟動
GlobalScope.launch {
//to do some thing
}
GlobalScope 實現(xiàn)了接口 CoroutineScope ,而 CoroutineScope 有 launch 方法,不阻塞線程
相關(guān)的源碼如下:
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)
}
運行結(jié)果:
start execute main
end execute main
launch start execute DefaultDispatcher-worker-1 @coroutine#1
launch end execute DefaultDispatcher-worker-1 @coroutine#1
Job
后臺的工作。從概念上講,作業(yè)是一種可取消的東西,它的生命周期最終將完成。Job 可以取消并且有簡單生命周期,它有三種狀態(tài):
| 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 //是否關(guān)閉
job.isCompleted //是否完成
job.cancel() //關(guān)閉
job.join() //掛起協(xié)程直到執(zhí)行完畢
job.start() //開始執(zhí)行
2.1.2 CoroutineScope啟動
CoroutineScope(context = EmptyCoroutineContext).launch {
// to do something
}
2.1.3 runBlocking {}啟動
runBlocking {}是創(chuàng)建一個新的協(xié)程同時阻塞當(dāng)前線程,直到協(xié)程結(jié)束。這個不應(yīng)該在協(xié)程中使用,主要是為main函數(shù)和測試設(shè)計的。
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 實現(xiàn)CoroutineScope接口,初始化上下文
如GlobalScope 是 CoroutineScope 的一個單例實現(xiàn)

2.2 四種啟動方式 CoroutineStart
public enum class CoroutineStart {
DEFAULT,
LAZY,
@ExperimentalCoroutinesApi
ATOMIC,
@ExperimentalCoroutinesApi
UNDISPATCHED;
}
| 模式 | 功能 |
|---|---|
| DEFAULT | 立即執(zhí)行協(xié)程體 |
| LAZY | 懶漢式,只有在需要的情況下運行 |
| ATOMIC | 立即執(zhí)行協(xié)程體,但在開始運行之前無法取消,實驗api |
| UNDISPATCHED | 立即在當(dāng)前線程執(zhí)行協(xié)程體,直到第一個 suspend 調(diào)用,實驗api |
2.2.1 DEFAULT
DEFAULT 是餓漢式啟動, launch 調(diào)用后,會立即進(jìn)入待調(diào)度狀態(tài),一旦調(diào)度器 OK 就可以開始執(zhí)行。
示例:
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")
運行結(jié)果:
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 后并不會有任何調(diào)度行為,協(xié)程體也自然不會進(jìn)入執(zhí)行狀態(tài),直到我們需要它執(zhí)行的時候。這其實就有點兒費解了,什么叫我們需要它執(zhí)行的時候呢?就是需要它的運行結(jié)果的時候, launch 調(diào)用后會返回一個 Job 實例,對于這種情況,我們可以:
- 調(diào)用 Job.start ,主動觸發(fā)協(xié)程的調(diào)度執(zhí)行
- 調(diào)用 Job.join ,隱式的觸發(fā)協(xié)程的調(diào)度執(zhí)行
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 的時候才有意義,在這里我們就簡單認(rèn)為 cancel 后協(xié)程會被取消掉,也就是不再執(zhí)行了。那么調(diào)用cancel 的時機(jī)不同,結(jié)果也是有差異的,例如協(xié)程調(diào)度之前、開始調(diào)度但尚未執(zhí)行、已經(jīng)開始執(zhí)行、執(zhí)行完畢等等。
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
協(xié)程在這種模式下會直接開始在當(dāng)前線程下執(zhí)行,直到第一個掛起點,這聽起來有點兒像前面的 ATOMIC ,不同之處在于UNDISPATCHED 不經(jīng)過任何調(diào)度器即開始執(zhí)行協(xié)程體。當(dāng)然遇到掛起點之后的執(zhí)行就取決于掛起點本身的邏輯以及上下文當(dāng)中的調(diào)度器了。
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")
