Androdi kotlin Coroutines(協(xié)程)詳解 (二)

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")
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容