Kotlin Coroutine(協程)系列:
1. Kotlin Coroutine(協程) 簡介
2. Kotlin Coroutine(協程) 基本知識bash
這篇文章主要介紹協程中的一些基本概念。網絡
Kotlin
中提供了關鍵字suspend
用來描述一個函數爲掛起函數,寫法以下:async
//官方提供的函數
suspend fun delay(timeMillis: Long) {
...
}
複製代碼
以上寫法就表明delay
函數爲一個掛起函數。函數
在前面一篇文章Kotlin Coroutine(協程) 簡介中我提到過掛起函數只會掛起當前協程,不會掛起阻塞當前協程所處的線程。事實上,想要執行協程就至少須要一個掛起函數,所以掛起函數是協程中一個很是重要的概念。post
suspend
能夠將普通函數、擴展函數、lambda表達式均標記爲掛起函數官方描述:爲協程定義了一個範圍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
協程上下文,包含了協程中的一些元素,主要有Job
和CoroutineDispatcher
協程的後臺任務,它有本身的生命週期,該任務能夠被取消。
Job
能夠有父Job
,當父Job
被取消時,其全部子Job
也會被取消。
Job
有三種狀態:
isActive
是否處於活動狀態isCompleted
是否完成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()
方法,該方法會等待該協程任務執行結束,該方法爲掛起函數。
它是Job
的子類,與Job
不一樣的是它能夠有返回值,而Job
是沒有返回值的。
經過調用Deferred
的await()
方法便可拿到返回值,而await()
方法也是一個掛起函數,所以調用該方法時會掛起當前協程,直到拿到返回值協程從新恢復執行。
Android
中協程結合Retrofit
發起網絡請求能夠考慮使用該類獲取請求結果
協程調度器,它能夠將協程的執行侷限在指定的線程中,它有四個默認的實現:
Dispatchers.Default
默認調度器,在使用launch
和async
等協程構造器建立協程時,若是不指定調度器則會使用此默認調度器,該調度器會讓協程在JVM
提供的共享線程池中執行Dispatchers.Main
主線程調度器,讓協程在主線程即UI線程中執行Dispatchers.IO
讓協程在IO線程(子線程)中執行,該調度器會與Dispatchers.Default
調度器共享同一個線程池Dispatchers.Unconfined
該調度器不指定協程在某個線程中執行。設置了該調度器的協程會在調用者線程中啓動執行直到第一個掛起點,掛起後,它將在掛起函數執行的線程中恢復,恢復的線程徹底取決於該掛起函數在哪一個線程執行。newSingleThreadContext
這是Kotlin
另外提供的一個調度器,它會爲協程啓動一個新的線程。一個專用的線程是一種很是昂貴的資源。 在真實的應用程序中二者都必須被釋放,當再也不須要的時候,使用 close 函數,或存儲在一個頂級變量中使它在整個應用程序中被重用。另外須要注意的是:協程調度器默認承襲外部協程的調度器。
這是一個全局的CoroutineScope
不會受任何Job約束,經過它建立的是全局協程,它會在整個應用的生命週期中運行,不能被取消
這是一個擴展的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線程中執行
這是一個全局的協程構建器,能夠在任何地方調用。
該構建器會建立一個阻塞當前線程的協程,因此該構建器不建議使用在協程內。
和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()}")
複製代碼
全局函數
切換協程上下文,通常主要用來切換協程所在的線程環境,如從主線程切換到IO線程。
調用該方法不會建立新的協程,同時是一個掛起函數
該方法會有一個返回值,其返回值爲withContext
中lambda表達式的返回值