Kotlin Coroutine(協程) 基本知識

Kotlin Coroutine(協程)系列:
1. Kotlin Coroutine(協程) 簡介
2. Kotlin Coroutine(協程) 基本知識bash

這篇文章主要介紹協程中的一些基本概念。網絡

掛起函數(suspend關鍵字)

Kotlin中提供了關鍵字suspend用來描述一個函數爲掛起函數,寫法以下:async

//官方提供的函數
suspend fun delay(timeMillis: Long) {
    ...
}
複製代碼

以上寫法就表明delay函數爲一個掛起函數。函數

在前面一篇文章Kotlin Coroutine(協程) 簡介中我提到過掛起函數只會掛起當前協程,不會掛起阻塞當前協程所處的線程。事實上,想要執行協程就至少須要一個掛起函數,所以掛起函數是協程中一個很是重要的概念。post

特色
  1. 掛起函數能用普通函數的方式獲取參數和返回值
  2. 調用掛起函數時,可能會掛起當前協程(若是掛起函數的相關調用已經有結果,那麼系統可能會選擇不掛起),而不會掛起所在的線程。
  3. 掛起函數執行結束後,協程會自動恢復執行,此時才能繼續執行掛起函數後續的代碼
  4. 掛起函數只能在協程或其餘掛起函數中調用,不然會編譯報錯
  5. suspend能夠將普通函數、擴展函數、lambda表達式均標記爲掛起函數

CoroutineScope

官方描述:爲協程定義了一個範圍this

Defines a scope for new coroutines.spa

也能夠理解爲協程的上下文環境,更通俗點你能夠將其看做爲一個協程。.net

咱們再來看下官方源碼中的定義:線程

public interface CoroutineScope {
    /** * Context of this scope. */
    public val coroutineContext: CoroutineContext
}
複製代碼

經過這個代碼咱們能夠看到CoroutineScope初始定義中只有一個協程上下文CoroutineContext對象,因此協程的上下文對象實際上是由CoroutineContext決定的,所以將CoroutineScope看做協程更好理解。code

CoroutineContext

協程上下文,包含了協程中的一些元素,主要有JobCoroutineDispatcher

Job

協程的後臺任務,它有本身的生命週期,該任務能夠被取消。

Job能夠有父Job,當父Job被取消時,其全部子Job也會被取消。

Job有三種狀態:

  1. isActive 是否處於活動狀態
  2. isCompleted 是否完成
  3. isCancelled 是否被取消

可參考下表:

State [isActive] [isCompleted] [isCancelled]
New (optional initial state) false false false
Active (default initial state) true false false
Completing (transient state) true false false
Cancelling (transient state) false false true
Cancelled (final state) false true true
Completed (final state) false true false

當建立協程開始執行並獲取到Job對象後,若是想等該協程執行結束再執行其餘的業務邏輯,那麼能夠調用Job.join()方法,該方法會等待該協程任務執行結束,該方法爲掛起函數。

Deferred

它是Job的子類,與Job不一樣的是它能夠有返回值,而Job是沒有返回值的。

經過調用Deferredawait()方法便可拿到返回值,而await()方法也是一個掛起函數,所以調用該方法時會掛起當前協程,直到拿到返回值協程從新恢復執行。

Android中協程結合Retrofit發起網絡請求能夠考慮使用該類獲取請求結果

CoroutineDispatcher

協程調度器,它能夠將協程的執行侷限在指定的線程中,它有四個默認的實現:

  1. Dispatchers.Default 默認調度器,在使用launchasync等協程構造器建立協程時,若是不指定調度器則會使用此默認調度器,該調度器會讓協程在JVM提供的共享線程池中執行
  2. Dispatchers.Main 主線程調度器,讓協程在主線程即UI線程中執行
  3. Dispatchers.IO 讓協程在IO線程(子線程)中執行,該調度器會與Dispatchers.Default調度器共享同一個線程池
  4. Dispatchers.Unconfined 該調度器不指定協程在某個線程中執行。設置了該調度器的協程會在調用者線程中啓動執行直到第一個掛起點,掛起後,它將在掛起函數執行的線程中恢復,恢復的線程徹底取決於該掛起函數在哪一個線程執行。
  5. newSingleThreadContext 這是Kotlin另外提供的一個調度器,它會爲協程啓動一個新的線程。一個專用的線程是一種很是昂貴的資源。 在真實的應用程序中二者都必須被釋放,當再也不須要的時候,使用 close 函數,或存儲在一個頂級變量中使它在整個應用程序中被重用。

另外須要注意的是:協程調度器默認承襲外部協程的調度器。

GlobalScope

這是一個全局的CoroutineScope不會受任何Job約束,經過它建立的是全局協程,它會在整個應用的生命週期中運行,不能被取消

launch函數

這是一個擴展的CoroutineScope實例方法,同時也是一個很經常使用的協程構建器。

經過其默認參數會建立一個不會阻塞當前線程且會當即執行的協程,該方法會返回一個Job對象,該方法默認承襲所在的CoroutineScope對象的調度器。

val scope = CoroutineScope(Dispatchers.Main + Job())
scrope.launch {
    //協程實現
}
複製代碼

上述代碼經過launch建立的協程會在UI線程中執行

val scope = CoroutineScope(Dispatchers.Main + Job())
scrope.launch(Dispatchers.IO) {
    //協程實現
}
複製代碼

上述代碼經過launch建立的協程會在IO線程中執行

runBlocking

這是一個全局的協程構建器,能夠在任何地方調用。

該構建器會建立一個阻塞當前線程的協程,因此該構建器不建議使用在協程內。

async

launch函數同樣,也是CoroutineScope的擴展實例方法,它也是一個經常使用的協程構建器,不一樣是它建立協程時返回的是Deferred,經過Deferred能夠拿到執行結果

val a = async {
    log("I'm computing a piece of the answer")
    6
}
val b = async {
    log("I'm computing another piece of the answer")
    7
}
log("The answer is ${a.await() * b.await()}")
複製代碼

delay

全局函數

  1. 讓協程休眠指定時間,相似於Java中的Thread.sleep的做用
  2. delay是一個掛起函數,調用後不會阻塞掛起當前線程
  3. 當協程的休眠時間到了以後,當前所處協程會從新恢復執行

withContext

切換協程上下文,通常主要用來切換協程所在的線程環境,如從主線程切換到IO線程。

調用該方法不會建立新的協程,同時是一個掛起函數

該方法會有一個返回值,其返回值爲withContext中lambda表達式的返回值

相關文章
相關標籤/搜索