国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

這篇具有很好參考價值的文章主要介紹了【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。


協(xié)程簡介

Kotlin 中的協(xié)程提供了一種全新處理并發(fā)的方式,可以在 Android 平臺上使用它來簡化異步執(zhí)行的代碼。協(xié)程是從 Kotlin 1.3 版本開始引入,但這一概念在編程世界誕生的黎明之際就有了,最早使用協(xié)程的編程語言可以追溯到 1967 年的 Simula 語言。
在過去幾年間,協(xié)程這個概念發(fā)展勢頭迅猛,現(xiàn)已經(jīng)被諸多主流編程語言采用,比如 JavascriptC#、Python、Ruby 以及 Go 等。Kotlin 的協(xié)程是基于來自其他語言的既定概念。

Android 平臺上,協(xié)程主要用來解決兩個問題:

  • 處理耗時任務(wù) (Long running tasks),這種任務(wù)常常會阻塞住主線程;
  • 保證主線程安全 (Main-safety) ,即確保安全地從主線程調(diào)用任何 suspend 函數(shù)。

從本質(zhì)上來說,協(xié)程就是一個輕量級的線程。

一、協(xié)程的基本使用

在使用協(xié)程之前,我們需要先引入Coroutine 的包

// Kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.32"

// 協(xié)程核心庫
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
// 協(xié)程Android支持庫
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3"
// 協(xié)程Java8支持庫
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.4.3"

創(chuàng)建協(xié)程的方式有很多種,這里不延伸協(xié)程的高級用法(熱數(shù)據(jù)通道Channel、冷數(shù)據(jù)流Flow.…),創(chuàng)建協(xié)程這里介紹常用的三種方式:

1.1、runBlocking 啟動

runBlocking {
    println("runBlocking 啟動一個協(xié)程")
}

runBlocking 啟動一個協(xié)程會阻塞調(diào)用它的線程,只到里面的代碼執(zhí)行結(jié)束,返回值是泛型T。

1.2、GlobalScope.launch 啟動

GlobalScope.launch {
    println("launch 啟動一個協(xié)程")
}

launch啟動一個協(xié)程不會阻塞調(diào)用線程,必須要在協(xié)程作用域(CoroutineScope)中才能調(diào)用,返回值是一個Job

1.3、GlobalScope.async 啟動

GlobalScope.async {
    println("async 啟動一個協(xié)程")
}

async啟動一個協(xié)程其實和launch 是一樣的,不同點在于async的返回參數(shù)是: Deferred Deferred<out T> : Job,它實現(xiàn)了一個Deferred接口,但是Deferred 繼承了job,Deferred和job 的不同點是,Deferred 里面定義了await 函數(shù),需要與await()掛起函數(shù)結(jié)合使用。

1.4、三種啟動方式的說明

  • runBlocking{} - 主要用于測試

    該方法的設(shè)計目的是讓suspend風(fēng)格編寫的庫能夠在常規(guī)阻塞代碼中使用,常在main方法和測試中使用。

  • GlobalScope.launch/async{} - 不推薦使用

    由于這樣啟動的協(xié)程存在啟動協(xié)程的組件已被銷毀但協(xié)程還存在的情況,極限情況下可能導(dǎo)致資源耗盡,因此并不推薦這樣啟動,尤其是在客戶端這種需要頻繁創(chuàng)建銷毀組件的場景。

二、Coroutine 源碼解析

這里我們使用CoroutineScope.launch{}的源碼為例,來深入了解Coroutine:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

上面是launch函數(shù)的定義,它以CoroutineScope的擴展函數(shù)的形成出現(xiàn),函數(shù)參數(shù)分別是:協(xié)程上下文CoroutineContext、協(xié)程啟動模式CoroutineStart、協(xié)程體,返回值是協(xié)程實例Job,其中CoroutineContext又包括了JobCoroutineDispatcher、CoroutineName。下面我們就一一介紹這些內(nèi)容:CoroutineContext、Job、CoroutineDispatcherCoroutineStart、CoroutineScope。

2.1、CoroutineContext

CoroutineContext: 協(xié)程上下文

  1. 線程行為、生命周期、異常以及調(diào)試
  2. 包含用戶定義的一些數(shù)據(jù)集合,這些數(shù)據(jù)與協(xié)程密切相關(guān)
  3. 它是一個有索引的 Element 實例集合,一個介于 set 和 map之間的數(shù)據(jù)結(jié)構(gòu)。每個 element 在這個集合有一個唯一的 Key
  • Job: 控制協(xié)程的生命周期

  • CoroutineDispatcher: 向合適的線程分發(fā)任務(wù)

  • CoroutineName: 協(xié)程的名稱,調(diào)試的時候很有用

  • CoroutineExceptionHandler: 處理未被捕捉的異常

CoroutineContext 有兩個非常重要的元素 — JobDispatcher,Job 是當(dāng)前的 Coroutine 實例而 Dispatcher 決定了當(dāng)前 Coroutine 執(zhí)行的線程,還可以添加CoroutineName,用于調(diào)試,添加 CoroutineExceptionHandler 用于捕獲異常,它們都實現(xiàn)了Element接口。

fun main() {
    val coroutineContext = Job() + Dispatchers.Default + CoroutineName("myContext")
    println("$coroutineContext,${coroutineContext[CoroutineName]}")
    val newCoroutineContext = coroutineContext.minusKey(CoroutineName)
    println("$newCoroutineContext")
}

輸出結(jié)果:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

CoroutineContext 源碼

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

通過源碼我可以看到CoroutineContext 定義了四個核心的操作:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

  • 操作符get
    可以通過 key 來獲取這個 Element。由于這是一個 get 操作符,所以可以像訪問 map 中的元素一樣使用 context[key]這種中括號的形式來訪問。
  • 操作符 plus
    Set.plus 擴展函數(shù)類似,返回一個新的 context 對象,新的對象里面包含了兩個里面的所有 Element,如果遇到重復(fù)的(Key 一樣的),那么用+號右邊的 Element 替代左邊的。+ 運算符可以很容易的用于結(jié)合上下文,但是有一個很重要的事情需要小心 —— 要注意它們結(jié)合的次序,因為這個 + 運算符是不對稱的。
  • fun fold(initial: R, operation: (R, Element) -> R): R
    Collection.fold 擴展函數(shù)類似,提供遍歷當(dāng)前 context 中所有 Element 的能力。
  • fun minusKey(key: Key<>): CoroutineContext
    返回一個上下文,其中包含該上下文中的元素,但不包含具有指定key的元素。

2.2、Job 源碼

Job 用于處理協(xié)程

對于每一個所創(chuàng)建的協(xié)程 (通過 launch 或者 async),它會返回一個 Job實例,該實例是協(xié)程的唯一標識,并且負責(zé)管理協(xié)程的生命周期
CoroutineScope.launch 函數(shù)返回的是一個 Job 對象,代表一個異步的任務(wù)。Job 具有生命周期并且可以取消。 Job 還可以有層級關(guān)系,一個Job可以包含多個子Job,當(dāng)父Job被取消后,所有的子Job也會被自動取消;當(dāng)子Job被取消或者出現(xiàn)異常后父Job也會被取消。
除了通過 CoroutineScope.launch 來創(chuàng)建Job對象之外,還可以通過 Job() 工廠方法來創(chuàng)建該對象。默認情況下,子Job的失敗將會導(dǎo)致父Job被取消,這種默認的行為可以通過 SupervisorJob 來修改。
具有多個子 Job 的父Job 會等待所有子Job完成(或者取消)后,自己才會執(zhí)行完成

Job 生命周期的狀態(tài)

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

一個任務(wù)可以包含一系列狀態(tài): 新創(chuàng)建 (New)、活躍 (Active)、完成中 (Completing)、已完成 (Completed)、取消中 (Cancelling) 和已取消 (Cancelled)。雖然我們無法直接訪問這些狀態(tài),但是我們可以訪問 Job 的屬性: isActive、isCancelledisCompleted。
如果協(xié)程處于活躍狀態(tài),協(xié)程運行出錯或者調(diào)用 job.cancel() 都會將當(dāng)前任務(wù)置為取消中 (Cancelling) 狀態(tài) (isActive = false, isCancelled = true)。當(dāng)所有的子協(xié)程都完成后,協(xié)程會進入已取消 (Cancelled) 狀態(tài),此時 isCompleted = true。

2.3、Job 的常用函數(shù)

這些函數(shù)都是線程安全的,所以可以直接在其他 Coroutine 中調(diào)用。

  • fun start(): Boolean
    調(diào)用該函數(shù)來啟動這個 Coroutine,如果當(dāng)前 Coroutine 還沒有執(zhí)行調(diào)用該函數(shù)返回 true,如果當(dāng)前 Coroutine 已經(jīng)執(zhí)行或者已經(jīng)執(zhí)行完畢,則調(diào)用該函數(shù)返回 false

  • fun cancel(cause: CancellationException? = null)
    通過可選的取消原因取消此作業(yè)。 原因可以用于指定錯誤消息或提供有關(guān)取消原因的其他詳細信息,以進行調(diào)試。

  • fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
    通過這個函數(shù)可以給 Job 設(shè)置一個完成通知,當(dāng) Job 執(zhí)行完成的時候會同步執(zhí)行這個通知函數(shù)。 回調(diào)的通知對象類型為:typealias CompletionHandler = (cause: Throwable?) -> Unit. CompletionHandler 參數(shù)代表了 Job 是如何執(zhí)行完成的。 cause 有下面三種情況:

    1. 如果 Job 是正常執(zhí)行完成的,則 cause 參數(shù)為 null
    1. 如果 Job 是正常取消的,則 cause 參數(shù)為 CancellationException 對象。這種情況不應(yīng)該當(dāng)做錯誤處理,這是任務(wù)正常取消的情形。所以一般不需要在錯誤日志中記錄這種情況。
    2. 其他情況表示 Job 執(zhí)行失敗了。

這個函數(shù)的返回值為 DisposableHandle 對象,如果不再需要監(jiān)控 Job 的完成情況了, 則可以調(diào)用 DisposableHandle.dispose 函數(shù)來取消監(jiān)聽。如果 Job 已經(jīng)執(zhí)行完了, 則無需調(diào)用 dispose 函數(shù)了,會自動取消監(jiān)聽。

  • suspend fun join()

join 函數(shù)和前面三個函數(shù)不同,這是一個 suspend 函數(shù)。所以只能在 Coroutine 內(nèi)調(diào)用。

這個函數(shù)會暫停當(dāng)前所處的 Coroutine直到該Coroutine執(zhí)行完成。所以 join 函數(shù)一般用來在另外一個 Coroutine 中等待 job 執(zhí)行完成后繼續(xù)執(zhí)行。當(dāng) Job 執(zhí)行完成后, job.join 函數(shù)恢復(fù),這個時候 job 這個任務(wù)已經(jīng)處于完成狀態(tài)了,而調(diào)用 job.joinCoroutine 還繼續(xù)處于 activie 狀態(tài)。

請注意,只有在其所有子級都完成后,作業(yè)才能完成

該函數(shù)的掛起是可以被取消的,并且始終檢查調(diào)用的CoroutineJob是否取消。如果在調(diào)用此掛起函數(shù)或?qū)⑵鋻炱饡r,調(diào)用CoroutineJob被取消或完成,則此函數(shù)將引發(fā) CancellationException。

2.4、SupervisorJob

SupervisorJob 是一個頂層函數(shù),定義如下:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

該函數(shù)創(chuàng)建了一個處于 active 狀態(tài)的supervisor job。如前所述, Job 是有父子關(guān)系的,如果子Job 失敗了父Job會自動失敗,這種默認的行為可能不是我們期望的。比如在 Activity 中有兩個子Job分別獲取一篇文章的評論內(nèi)容和作者信息。如果其中一個失敗了,我們并不希望父Job自動取消,這樣會導(dǎo)致另外一個子Job也被取消。而SupervisorJob就是這么一個特殊的 Job,里面的子Job不相互影響,一個子Job失敗了,不影響其他子Job的執(zhí)行。SupervisorJob(parent:Job?) 具有一個parent參數(shù),如果指定了這個參數(shù),則所返回的 Job 就是參數(shù) parent 的子Job。如果 Parent Job 失敗了或者取消了,則這個 Supervisor Job 也會被取消。當(dāng) Supervisor Job被取消后,所有 Supervisor Job 的子Job也會被取消。

MainScope() 的實現(xiàn)就使用了 SupervisorJob 和一個 Main Dispatcher

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

但是SupervisorJob是很容易被誤解的,它和協(xié)程異常處理、子協(xié)程所屬Job類型還有域有很多讓人混淆的地方,具體異常處理可以看Google的這一篇文章:協(xié)程中的取消和異常 | 異常處理詳解

三、suspend關(guān)鍵字

這個 suspend 關(guān)鍵字,既然它并不是真正實現(xiàn)掛起,那它的作用是什么?

它其實是一個提醒。

函數(shù)的創(chuàng)建者對函數(shù)的使用者的提醒:我是一個耗時函數(shù),我被我的創(chuàng)建者用掛起的方式放在后臺運行,所以請在協(xié)程里調(diào)用我。

掛起的操作 —— 也就是切線程,依賴的是掛起函數(shù)里面的實際代碼,而不是這個關(guān)鍵字。

所以這個關(guān)鍵字,只是一個提醒。

3.1、CoroutineDispatcher 調(diào)度器

  • Dispatchers.Default

    默認的調(diào)度器,適合處理后臺計算,是一個CPU密集型任務(wù)調(diào)度器。如果創(chuàng)建 Coroutine 的時候沒有指定 dispatcher,則一般默認使用這個作為默認值。Default dispatcher 使用一個共享的后臺線程池來運行里面的任務(wù)。注意它和IO共享線程池,只不過限制了最大并發(fā)數(shù)不同。

  • Dispatchers.IO

    顧名思義這是用來執(zhí)行阻塞 IO 操作的,是和Default共用一個共享的線程池來執(zhí)行里面的任務(wù)。根據(jù)同時運行的任務(wù)數(shù)量,在需要的時候會創(chuàng)建額外的線程,當(dāng)任務(wù)執(zhí)行完畢后會釋放不需要的線程。

  • Dispatchers.Unconfined

    由于Dispatchers.Unconfined未定義線程池,所以執(zhí)行的時候默認在啟動線程。遇到第一個掛起點,之后由調(diào)用resume的線程決定恢復(fù)協(xié)程的線程。

  • Dispatchers.Main

    指定執(zhí)行的線程是主線程,在Android上就是UI線程。

由于子Coroutine 會繼承父Coroutine 的 context,所以為了方便使用,我們一般會在 父Coroutine 上設(shè)定一個 Dispatcher,然后所有 子Coroutine 自動使用這個 Dispatcher。

3.2、CoroutineStart 協(xié)程啟動模式

  • CoroutineStart.DEFAULT

    協(xié)程創(chuàng)建后立即開始調(diào)度,在調(diào)度前如果協(xié)程被取消,其將直接進入取消響應(yīng)的狀態(tài)雖然是立即調(diào)度,但也有可能在執(zhí)行前被取消

  • CoroutineStart.ATOMIC

    協(xié)程創(chuàng)建后立即開始調(diào)度,協(xié)程執(zhí)行到第一個掛起點之前不響應(yīng)取消
    雖然是立即調(diào)度,但其將調(diào)度和執(zhí)行兩個步驟合二為一了,就像它的名字一樣,其保證調(diào)度和執(zhí)行是原子操作,因此協(xié)程也一定會執(zhí)行

  • CoroutineStart.LAZY

    只要協(xié)程被需要時,包括主動調(diào)用該協(xié)程的start、join或者await等函數(shù)時才會開始調(diào)度,如果調(diào)度前就被取消,協(xié)程將直接進入異常結(jié)束狀態(tài)

  • CoroutineStart.UNDISPATCHED

    協(xié)程創(chuàng)建后立即在當(dāng)前函數(shù)調(diào)用棧中執(zhí)行,直到遇到第一個真正掛起的點
    是立即執(zhí)行,因此協(xié)程一定會執(zhí)行

這些啟動模式的設(shè)計主要是為了應(yīng)對某些特殊的場景。業(yè)務(wù)開發(fā)實踐中通常使用DEFAULTLAZY這兩個啟動模式就夠了

3.3、CoroutineScope - 協(xié)程作用域

定義協(xié)程必須指定其 CoroutineScopeCoroutineScope 可以對協(xié)程進行追蹤,即使協(xié)程被掛起也是如此。同調(diào)度程序 (Dispatcher) 不同,CoroutineScope 并不運行協(xié)程,它只是確保您不會失去對協(xié)程的追蹤。為了確保所有的協(xié)程都會被追蹤,Kotlin 不允許在沒有使用 CoroutineScope 的情況下啟動新的協(xié)程。CoroutineScope 可被看作是一個具有超能力的 ExecutorService 的輕量級版本。CoroutineScope 會跟蹤所有協(xié)程,同樣它還可以取消由它所啟動的所有協(xié)程。這在 Android 開發(fā)中非常有用,比如它能夠在用戶離開界面時停止執(zhí)行協(xié)程。

Coroutine 是輕量級的線程,并不意味著就不消耗系統(tǒng)資源。 當(dāng)異步操作比較耗時的時候,或者當(dāng)異步操作出現(xiàn)錯誤的時候,需要把這個 Coroutine 取消掉來釋放系統(tǒng)資源。在 Android 環(huán)境中,通常每個界面(Activity、Fragment等)啟動的 Coroutine 只在該界面有意義,如果用戶在等待 Coroutine 執(zhí)行的時候退出了這個界面,則再繼續(xù)執(zhí)行這個 Coroutine 可能是沒必要的。另外 Coroutine 也需要在適當(dāng)?shù)?context 中執(zhí)行,否則會出現(xiàn)錯誤,比如在非 UI 線程去訪問 View。 所以 Coroutine 在設(shè)計的時候,要求在一個范圍(Scope)內(nèi)執(zhí)行,這樣當(dāng)這個 Scope 取消的時候,里面所有的子 Coroutine 也自動取消。所以要使用 Coroutine 必須要先創(chuàng)建一個對應(yīng)的 CoroutineScope。

CoroutineScope 接口

public interface CoroutineScope {
    public val coroutineContext: CoroutineContext
}

CoroutineScope 只是定義了一個新 Coroutine 的執(zhí)行 Scope。每個 coroutine builder都是 CoroutineScope 的擴展函數(shù),并且自動的繼承了當(dāng)前 ScopecoroutineContext

3.4、分類及行為規(guī)則

官方框架在實現(xiàn)復(fù)合協(xié)程的過程中也提供了作用域,主要用以明確寫成之間的父子關(guān)系,以及對于取消或者異常處理等方面的傳播行為。該作用域包括以下三種:

  • 頂級作用域
    沒有父協(xié)程的協(xié)程所在的作用域為頂級作用域。

  • 協(xié)同作用域
    協(xié)程中啟動新的協(xié)程,新協(xié)程為所在協(xié)程的子協(xié)程,這種情況下,子協(xié)程所在的作用域默認為協(xié)同作用域。此時子協(xié)程拋出的未捕獲異常,都將傳遞給父協(xié)程處理,父協(xié)程同時也會被取消。

    coroutineScope 內(nèi)部的異常會向上傳播,子協(xié)程未捕獲的異常會向上傳遞給父協(xié)程,任何一個子協(xié)程異常退出,會導(dǎo)致整體的退出

    【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

  • 主從作用域
    與協(xié)同作用域在協(xié)程的父子關(guān)系上一致,區(qū)別在于,處于該作用域下的協(xié)程出現(xiàn)未捕獲的異常時,不會將異常向上傳遞給父協(xié)程。

    supervisorScope屬于主從作用域,會繼承父協(xié)程的上下文,它的特點就是子協(xié)程的異常不會影響父協(xié)程

    【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

除了三種作用域中提到的行為以外,父子協(xié)程之間還存在以下規(guī)則:

  • 父協(xié)程被取消,則所有子協(xié)程均被取消。由于協(xié)同作用域和主從作用域中都存在父子協(xié)程關(guān)系,因此此條規(guī)則都適用。
  • 父協(xié)程需要等待子協(xié)程執(zhí)行完畢之后才會最終進入完成狀態(tài),不管父協(xié)程自身的協(xié)程體是否已經(jīng)執(zhí)行完。
  • 子協(xié)程會繼承父協(xié)程的協(xié)程上下文中的元素,如果自身有相同key的成員,則覆蓋對應(yīng)的key,覆蓋的效果僅限自身范圍內(nèi)有效。

四、Android中協(xié)程的使用及取消和異常

普通協(xié)程如果產(chǎn)生未處理異常會將此異常傳播至它的父協(xié)程,然后父協(xié)程會取消所有的子協(xié)程、取消自己、將異常繼續(xù)向上傳遞。下面拿一個官方的圖來示例這個過程:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

這種情況有的時候并不是我們想要的,我們更希望一個協(xié)程在產(chǎn)生異常時,不影響其他協(xié)程的執(zhí)行,在上文中我們也提到了一些解決方案,下面我們就在實踐一下。

4.1、使用SupervisorJob

    //    使用官方庫的 MainScope()獲取一個協(xié)程作用域用于創(chuàng)建協(xié)程
    private val mScope = MainScope();

    fun onClickCoroutine(view: View) {

        mScope.launch(Dispatchers.Default) {
            println("我是第一個協(xié)程")
        }

        mScope.launch(Dispatchers.Default) {
            println("我是第二個協(xié)程")
            throw RuntimeException("RuntimeException 就是一個異常")
        }

        mScope.launch(Dispatchers.Default) {
            println("我是第三個協(xié)程")
        }
    }

代碼執(zhí)行結(jié)果:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

MainScope()之前提到過了,它的實現(xiàn)就是用了SupervisorJob。執(zhí)行結(jié)果就是 第二個協(xié)程 拋出異常后,第三個協(xié)程 正常執(zhí)行了,但是程序崩了,因為我們沒有處理這個異常,下面完善一下代碼

異常處理:

fun onClickCoroutine(view: View) {

    mScope.launch(Dispatchers.Default) {
        println("我是第一個協(xié)程")
    }

    mScope.launch(Dispatchers.Default + CoroutineExceptionHandler { coroutineContext, throwable ->
        println(
            "CoroutineExceptionHandler: $throwable"
        )
    }) {
        println("我是第二個協(xié)程")
        throw RuntimeException("RuntimeException 就是一個異常")
    }

    mScope.launch(Dispatchers.Default) {
        println("我是第三個協(xié)程")
    }
}

打印結(jié)果:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

程序沒有崩潰,并且異常處理的打印也輸出了,這就達到了我們想要的效果。但是要注意一個事情,這幾個子協(xié)程的父級是SupervisorJob,但是他們再有子協(xié)程的話,他們的子協(xié)程的父級就不是SupervisorJob了,所以當(dāng)它們產(chǎn)生異常時,就不是我們演示的效果了。我們使用一個官方的圖來解釋這個關(guān)系:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

如圖所示,新的協(xié)程被創(chuàng)建時,會生成新的 Job 實例替代 SupervisorJob

4.2、使用supervisorScope

這個作用域上文中也有提到,使用supervisorScope也可以達到我們想要的效果,上代碼:

fun onClickCoroutine(view: View) {

    val coroutineScope = CoroutineScope(Job() + Dispatchers.Default)

    coroutineScope.launch(CoroutineExceptionHandler { coroutineContext, throwable ->
        println(
            "CoroutineExceptionHandler: $throwable"
        )
    }) {
        supervisorScope {
            launch {
                println("我是第一個協(xié)程")
            }
            launch {
                println("我是第二個協(xié)程")
                throw RuntimeException("RuntimeException 就是一個異常")
            }
            launch {
                println("我是第三個協(xié)程")
            }
        }
    }
}

運行結(jié)果

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

可以看到已經(jīng)達到了我們想要的效果,但是如果將supervisorScope換成coroutineScope,結(jié)果就不是這樣了。最終還是拿官方的圖來展示:

【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階

文章到這里就結(jié)束了,本文參考Quyunshuo,如有侵權(quán),請聯(lián)系刪除。文章來源地址http://www.zghlxwxcb.cn/news/detail-466602.html

到了這里,關(guān)于【kotlin 協(xié)程】萬字協(xié)程 一篇完成kotlin 協(xié)程進階的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • Kotlin 協(xié)程一 —— 協(xié)程 Coroutine

    1.1.1基本定義 進程 進程是一個具有一定獨立功能的程序在一個數(shù)據(jù)集上的一次動態(tài)執(zhí)行的過程,是操作系統(tǒng)進行資源分配和調(diào)度的一個獨立單位,是應(yīng)用程序運行的載體。 進程是資源分配的最小單位,在單核CPU中,同一時刻只有一個程序在內(nèi)存中被CPU調(diào)用運行。 線程 基本的

    2024年02月05日
    瀏覽(20)
  • Kotlin協(xié)程-從一到多

    上一篇文章,我介紹了Kotlin協(xié)程的創(chuàng)建,使用,協(xié)作等內(nèi)容。本篇將引入更多的使用場景,繼續(xù)帶你走進協(xié)程世界。 常用編程語言都會內(nèi)置對同一類型不同對象的數(shù)據(jù)集表示,我們通常稱之為容器類。不同的容器類適用于不同的使用場景。Kotlin的 Flow 就是在異步計算的需求下

    2024年02月09日
    瀏覽(19)
  • Android Kotlin 協(xié)程初探

    維基百科:協(xié)程,英文Coroutine [k?ru’tin] (可入廳),是計算機程序的一類組件,推廣了協(xié)作式多任務(wù)的子程序,允許執(zhí)行被掛起與被恢復(fù)。 作為Google欽定的Android開發(fā)首選語言Kotlin,協(xié)程并不是 Kotlin 提出來的新概念,目前有協(xié)程概念的編程語言有Lua語言、Python語言、Go語言

    2024年02月08日
    瀏覽(27)
  • Kotlin協(xié)程-從理論到實戰(zhàn)

    上一篇文章從理論上對Kotlin協(xié)程進行了部分說明,本文將在上一篇的基礎(chǔ)上,從實戰(zhàn)出發(fā),繼續(xù)協(xié)程之旅。 在Kotlin中,要想使用協(xié)程,首先需要使用協(xié)程創(chuàng)建器創(chuàng)建,但還有個前提——協(xié)程作用域( CoroutineScope )。在早期的Kotlin實現(xiàn)中,協(xié)程創(chuàng)建器是一等函數(shù),也就是說我們隨

    2024年02月09日
    瀏覽(21)
  • Kotlin協(xié)程學(xué)習(xí)之-02

    協(xié)程的基本使用 GlobalScope.launch 生命周期與進程一致,且無法取消 runBlocking 會阻塞線程,一般在測試階段可以使用 val coroutineScope = CoroutineScope(context) coroutineScope.launch 通過context參數(shù)去管理和控制協(xié)程的生命周期 用法 val coroutineScope = CoroutineScope(context) coroutineScope.launch(Dispatche

    2024年01月22日
    瀏覽(19)
  • Kotlin 協(xié)程基礎(chǔ)使用學(xué)習(xí)

    Kotlin 協(xié)程基礎(chǔ)使用學(xué)習(xí)

    原文: Kotlin 協(xié)程基礎(chǔ)使用學(xué)習(xí)-Stars-One的雜貨小窩 本篇閱讀可能需要以下知識,否則可能閱讀會有些困難 客戶端開發(fā)基礎(chǔ)(Android開發(fā)或JavaFx開發(fā)) Java多線程基礎(chǔ) kotlin基礎(chǔ) 本文盡量以使用為主,以代碼為輔講解,不提及過深協(xié)程底層代碼邏輯,僅做一個基礎(chǔ)入門來快速上手學(xué)習(xí)(斷斷

    2024年03月18日
    瀏覽(51)
  • Kotlin 協(xié)程 - 多路復(fù)用 select()

    ? ? ? ? 又叫選擇表達式,是一個掛起函數(shù),可以同時等待多個掛起結(jié)果,只取用最快恢復(fù)的那個值(即多種方式獲取數(shù)據(jù),哪個更快返回結(jié)果就用哪個)。 ????????同時到達 select() 會優(yōu)先選擇先寫子表達式,想隨機(公平)的話使用 selectUnbiased() 替換?。 ????????能

    2024年02月10日
    瀏覽(29)
  • 協(xié)程 VS 線程,Kotlin技術(shù)精講

    協(xié)程 VS 線程,Kotlin技術(shù)精講

    協(xié)程(coroutines)是一種并發(fā)設(shè)計模式,您可以在Android 平臺上使用它來簡化異步執(zhí)行的代碼。協(xié)程是在版本 1.3 中添加到 Kotlin 的,它基于來自其他語言的既定概念。 在 Android 上,協(xié)程有助于管理長時間運行的任務(wù),如果管理不當(dāng),這些任務(wù)可能會阻塞主線程并導(dǎo)致應(yīng)用無響應(yīng)。

    2024年02月09日
    瀏覽(22)
  • 【Kotlin】協(xié)程的字節(jié)碼原理

    【Kotlin】協(xié)程的字節(jié)碼原理

    前言 協(xié)程是Koltin語言最重要的特性之一,也是最難理解的特性。網(wǎng)上關(guān)于kotlin協(xié)程的描述也是五花八門,有人說它是輕量級線程,有人說它是無阻塞式掛起,有人說它是一個異步框架等等,眾說紛蕓。甚至還有人出了書籍專門介紹kotlin協(xié)程。 筆者剛開始接觸這個概念也是一

    2024年01月18日
    瀏覽(17)
  • Kotlin 協(xié)程 supervisorScope {} 運行崩潰解決

    簡單介紹 supervisorScope 函數(shù),它用于創(chuàng)建一個使用了 SupervisorJob 的 coroutineScope, 該作用域的特點:拋出的異常,不會 連鎖取消 同級協(xié)程和父協(xié)程。 看過很多? supervisorScope {} ? 文檔的使用,我照抄一摸一樣的代碼,運行就崩潰,最后找到了解決方法,應(yīng)該是kotlin版本更新做過

    2024年01月25日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包