精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

在 Android 開發(fā)中使用協(xié)程 | 上手指南

移動(dòng)開發(fā) Android
本篇文章,我們探討了如何在 Android 的 ViewModel 中啟動(dòng)協(xié)程,以及如何在代碼中運(yùn)用結(jié)構(gòu)化并發(fā),來讓我們的代碼更易于維護(hù)和理解。

接上篇文章《在 Android 開發(fā)中使用協(xié)程 | 背景介紹

本文是介紹 Android 協(xié)程系列中的第二部分,這篇文章主要會(huì)介紹如何使用協(xié)程來處理任務(wù),并且能在任務(wù)開始執(zhí)行后保持對(duì)它的追蹤。

[[323364]]

保持對(duì)協(xié)程的追蹤

本系列文章的第一篇,我們探討了協(xié)程適合用來解決哪些問題。這里再簡(jiǎn)單回顧一下,協(xié)程適合解決以下兩個(gè)常見的編程問題:

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

協(xié)程通過在常規(guī)函數(shù)之上增加 suspend 和 resume 兩個(gè)操作來解決上述問題。當(dāng)某個(gè)特定的線程上的所有協(xié)程被 suspend 后,該線程便可騰出資源去處理其他任務(wù)。

協(xié)程自身并不能夠追蹤正在處理的任務(wù),但是有成百上千個(gè)協(xié)程并對(duì)它們同時(shí)執(zhí)行掛起操作并沒有太大問題。協(xié)程是輕量級(jí)的,但處理的任務(wù)卻不一定是輕量的,比如讀取文件或者發(fā)送網(wǎng)絡(luò)請(qǐng)求。

使用代碼來手動(dòng)追蹤上千個(gè)協(xié)程是非常困難的,您可以嘗試對(duì)所有協(xié)程進(jìn)行跟蹤,手動(dòng)確保它們都完成了或者都被取消了,那么代碼會(huì)臃腫且易出錯(cuò)。如果代碼不是很完美,就會(huì)失去對(duì)協(xié)程的追蹤,也就是所謂 "work leak" 的情況。

任務(wù)泄漏 (work leak) 是指某個(gè)協(xié)程丟失無法追蹤,它類似于內(nèi)存泄漏,但比它更加糟糕,這樣丟失的協(xié)程可以恢復(fù)自己,從而占用內(nèi)存、CPU、磁盤資源,甚至?xí)l(fā)起一個(gè)網(wǎng)絡(luò)請(qǐng)求,而這也意味著它所占用的這些資源都無法得到重用。

泄漏協(xié)程會(huì)浪費(fèi)內(nèi)存、CPU、磁盤資源,甚至發(fā)送一個(gè)無用的網(wǎng)絡(luò)請(qǐng)求。

為了能夠避免協(xié)程泄漏,Kotlin 引入了結(jié)構(gòu)化并發(fā) (structured concurrency) 機(jī)制,它是一系列編程語言特性和實(shí)踐指南的結(jié)合,遵循它能幫助您追蹤到所有運(yùn)行于協(xié)程中的任務(wù)。

在 Android 平臺(tái)上,我們可以使用結(jié)構(gòu)化并發(fā)來做到以下三件事:

  • 取消任務(wù) —— 當(dāng)某項(xiàng)任務(wù)不再需要時(shí)取消它;
  • 追蹤任務(wù) —— 當(dāng)任務(wù)正在執(zhí)行時(shí),追蹤它;
  • 發(fā)出錯(cuò)誤信號(hào) —— 當(dāng)協(xié)程失敗時(shí),發(fā)出錯(cuò)誤信號(hào)表明有錯(cuò)誤發(fā)生。

接下來我們對(duì)以上幾點(diǎn)一一進(jìn)行探討,看看結(jié)構(gòu)化并發(fā)是如何幫助能夠追蹤所有協(xié)程,而不會(huì)導(dǎo)致泄漏出現(xiàn)的。

結(jié)構(gòu)化并發(fā):

https://kotlinlang.org/docs/reference/coroutines/basics.html#structured-concurrency

借助 scope 來取消任務(wù)

在 Kotlin 中,定義協(xié)程必須指定其 CoroutineScope 。CoroutineScope 可以對(duì)協(xié)程進(jìn)行追蹤,即使協(xié)程被掛起也是如此。同第一篇文章中講到的調(diào)度程序 (Dispatcher) 不同,CoroutineScope 并不運(yùn)行協(xié)程,它只是確保您不會(huì)失去對(duì)協(xié)程的追蹤。

為了確保所有的協(xié)程都會(huì)被追蹤,Kotlin 不允許在沒有使用 CoroutineScope 的情況下啟動(dòng)新的協(xié)程。CoroutineScope 可被看作是一個(gè)具有超能力的 ExecutorService 的輕量級(jí)版本。它能啟動(dòng)新的協(xié)程,同時(shí)這個(gè)協(xié)程還具備我們?cè)诘谝徊糠炙f的 suspend 和 resume 的優(yōu)勢(shì)。

CoroutineScope 會(huì)跟蹤所有協(xié)程,同樣它還可以取消由它所啟動(dòng)的所有協(xié)程。這在 Android 開發(fā)中非常有用,比如它能夠在用戶離開界面時(shí)停止執(zhí)行協(xié)程。

CoroutineScope 會(huì)跟蹤所有協(xié)程,并且可以取消由它所啟動(dòng)的所有協(xié)程。

啟動(dòng)新的協(xié)程

需要特別注意的是,您不能隨便就在某個(gè)地方調(diào)用 suspend 函數(shù),suspend 和 resume 機(jī)制要求您從常規(guī)函數(shù)中切換到協(xié)程。

有兩種方式能夠啟動(dòng)協(xié)程,它們分別適用于不同的場(chǎng)景:

  • launch 構(gòu)建器適合執(zhí)行 "一勞永逸" 的工作,意思就是說它可以啟動(dòng)新協(xié)程而不將結(jié)果返回給調(diào)用方;
  • async 構(gòu)建器可啟動(dòng)新協(xié)程并允許您使用一個(gè)名為 await 的掛起函數(shù)返回 result。

通常,您應(yīng)使用 launch 從常規(guī)函數(shù)中啟動(dòng)新協(xié)程。因?yàn)槌R?guī)函數(shù)無法調(diào)用 await (記住,它無法直接調(diào)用 suspend 函數(shù)),所以將 async 作為協(xié)程的主要啟動(dòng)方法沒有多大意義。稍后我們會(huì)討論應(yīng)該如何使用 async。

您應(yīng)該改為使用 coroutine scope 調(diào)用 launch 方法來啟動(dòng)協(xié)程。

  1. scope.launch { 
  2.     // 這段代碼在作用域里啟動(dòng)了一個(gè)新協(xié)程 
  3.    // 它可以調(diào)用掛起函數(shù) 
  4.    fetchDocs() 

您可以將 launch 看作是將代碼從常規(guī)函數(shù)送往協(xié)程世界的橋梁。在 launch 函數(shù)體內(nèi),您可以調(diào)用 suspend 函數(shù)并能夠像我們上一篇介紹的那樣保證主線程安全。

Launch 是將代碼從常規(guī)函數(shù)送往協(xié)程世界的橋梁。

注意:launch 和 async 之間的很大差異是它們對(duì)異常的處理方式不同。async 期望最終是通過調(diào)用 await 來獲取結(jié)果 (或者異常),所以默認(rèn)情況下它不會(huì)拋出異常。這意味著如果使用 async 啟動(dòng)新的協(xié)程,它會(huì)靜默地將異常丟棄。

由于 launch 和 async 僅能夠在 CouroutineScope 中使用,所以任何您所創(chuàng)建的協(xié)程都會(huì)被該 scope 追蹤。Kotlin 禁止您創(chuàng)建不能夠被追蹤的協(xié)程,從而避免協(xié)程泄漏。

  • launchhttps://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html
  • asynchttps://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html

在 ViewModel 中啟動(dòng)協(xié)程

既然 CoroutineScope 會(huì)追蹤由它啟動(dòng)的所有協(xié)程,而 launch 會(huì)創(chuàng)建一個(gè)新的協(xié)程,那么您應(yīng)該在什么地方調(diào)用 launch 并將其放在 scope 中呢? 又該在什么時(shí)候取消在 scope 中啟動(dòng)的所有協(xié)程呢?

在 Android 平臺(tái)上,您可以將 CoroutineScope 實(shí)現(xiàn)與用戶界面相關(guān)聯(lián)。這樣可讓您避免泄漏內(nèi)存或者對(duì)不再與用戶相關(guān)的 Activities 或 Fragments 執(zhí)行額外的工作。當(dāng)用戶通過導(dǎo)航離開某界面時(shí),與該界面相關(guān)的 CoroutineScope 可以取消掉所有不需要的任務(wù)。

結(jié)構(gòu)化并發(fā)能夠保證當(dāng)某個(gè)作用域被取消后,它內(nèi)部所創(chuàng)建的所有協(xié)程也都被取消。

當(dāng)將協(xié)程同 Android 架構(gòu)組件 (Android Architecture Components) 集成起來時(shí),您往往會(huì)需要在 ViewModel 中啟動(dòng)協(xié)程。因?yàn)榇蟛糠值娜蝿?wù)都是在這里開始進(jìn)行處理的,所以在這個(gè)地方啟動(dòng)是一個(gè)很合理的做法,您也不用擔(dān)心旋轉(zhuǎn)屏幕方向會(huì)終止您所創(chuàng)建的協(xié)程。

從生命周期感知型組件 (AndroidX Lifecycle) 的 2.1.0 版本開始 (發(fā)布于 2019 年 9 月),我們通過添加擴(kuò)展屬性 ViewModel.viewModelScope 在 ViewModel 中加入了協(xié)程的支持。

看看如下示例:

  1. class MyViewModel(): ViewModel() { 
  2.     fun userNeedsDocs() { 
  3.        // 在 ViewModel 中啟動(dòng)新的協(xié)程 
  4.         viewModelScope.launch { 
  5.             fetchDocs() 
  6.         } 
  7.     } 

當(dāng) viewModelScope 被清除 (當(dāng) onCleared() 回調(diào)被調(diào)用時(shí)) 之后,它將自動(dòng)取消它所啟動(dòng)的所有協(xié)程。這是一個(gè)標(biāo)準(zhǔn)做法,如果一個(gè)用戶在尚未獲取到數(shù)據(jù)時(shí)就關(guān)閉了應(yīng)用,這時(shí)讓請(qǐng)求繼續(xù)完成就純粹是在浪費(fèi)電量。

為了提高安全性,CoroutineScope 會(huì)進(jìn)行自行傳播。也就是說,如果某個(gè)協(xié)程啟動(dòng)了另一個(gè)新的協(xié)程,它們都會(huì)在同一個(gè) scope 中終止運(yùn)行。這意味著,即使當(dāng)某個(gè)您所依賴的代碼庫從您創(chuàng)建的 viewModelScope 中啟動(dòng)某個(gè)協(xié)程,您也有方法將其取消。

注意:協(xié)程被掛起時(shí),系統(tǒng)會(huì)以拋出 CancellationException 的方式協(xié)作取消協(xié)程。捕獲頂級(jí)異常 (如Throwable) 的異常處理程序?qū)⒉东@此異常。如果您做異常處理時(shí)消費(fèi)了這個(gè)異常,或從未進(jìn)行 suspend 操作,那么協(xié)程將會(huì)徘徊于半取消 (semi-canceled) 狀態(tài)下。

所以,當(dāng)您需要將一個(gè)協(xié)程同 ViewModel 的生命周期保持一致時(shí),使用 viewModelScope 來從常規(guī)函數(shù)切換到協(xié)程中。然后,viewModelScope 會(huì)自動(dòng)為您取消協(xié)程,因此在這里哪怕是寫了死循環(huán)也是完全不會(huì)產(chǎn)生泄漏。如下示例:

  1. fun runForever() { 
  2.     // 在 ViewModel 中啟動(dòng)新的協(xié)程 
  3.     viewModelScope.launch { 
  4.         // 當(dāng) ViewModel 被清除后,下列代碼也會(huì)被取消 
  5.         while(true) { 
  6.             delay(1_000) 
  7.            // 每過 1 秒做點(diǎn)什么 
  8.         } 
  9.     } 

通過使用 viewModelScope,可以確保所有的任務(wù),包含死循環(huán)在內(nèi),都可以在不需要的時(shí)候被取消掉。

協(xié)作取消:

https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html#cancellation-and-timeouts

任務(wù)追蹤

使用協(xié)程來處理任務(wù)對(duì)于很多代碼來說真的很方便。啟動(dòng)協(xié)程,進(jìn)行網(wǎng)絡(luò)請(qǐng)求,將結(jié)果寫入數(shù)據(jù)庫,一切都很自然流暢。

但有時(shí)候,可能會(huì)遇到稍微復(fù)雜點(diǎn)的問題,例如您需要在一個(gè)協(xié)程中同時(shí)處理兩個(gè)網(wǎng)絡(luò)請(qǐng)求,這種情況下需要啟動(dòng)更多協(xié)程。

想要?jiǎng)?chuàng)建多個(gè)協(xié)程,可以在 suspend function 中使用名為 coroutineScope 或 supervisorScope 這樣的構(gòu)造器來啟動(dòng)多個(gè)協(xié)程。但是這個(gè) API 說實(shí)話,有點(diǎn)令人困惑。coroutineScope 構(gòu)造器和 CoroutineScope 這兩個(gè)的區(qū)別只是一個(gè)字符之差,但它們卻是完全不同的東西。

另外,如果隨意啟動(dòng)新協(xié)程,可能會(huì)導(dǎo)致潛在的任務(wù)泄漏 (work leak)。調(diào)用方可能感知不到啟用了新的協(xié)程,也就意味著無法對(duì)其進(jìn)行追蹤。

為了解決這個(gè)問題,結(jié)構(gòu)化并發(fā)發(fā)揮了作用,它保證了當(dāng) suspend 函數(shù)返回時(shí),就意味著它所處理的任務(wù)也都已完成。

結(jié)構(gòu)化并發(fā)保證了當(dāng) suspend 函數(shù)返回時(shí),它所處理任務(wù)也都已完成。

示例使用 coroutineScope 來獲取兩個(gè)文檔內(nèi)容:

  1. suspend fun fetchTwoDocs() { 
  2.     coroutineScope { 
  3.         launch { fetchDoc(1) } 
  4.         async { fetchDoc(2) } 
  5.     } 

在這個(gè)示例中,同時(shí)從網(wǎng)絡(luò)中獲取兩個(gè)文檔數(shù)據(jù),第一個(gè)是通過 launch 這樣 "一勞永逸" 的方式啟動(dòng)協(xié)程,這意味著它不會(huì)返回任何結(jié)果給調(diào)用方。

第二個(gè)是通過 async 的方式獲取文檔,所以是會(huì)有返回值返回的。不過上面示例有一點(diǎn)奇怪,因?yàn)橥ǔ碇v兩個(gè)文檔的獲取都應(yīng)該使用 async,但這里我僅僅是想舉例來說明可以根據(jù)需要來選擇使用 launch 還是 async,或者是對(duì)兩者進(jìn)行混用。

coroutineScope 和 supervisorScope 可以讓您安全地從 suspend 函數(shù)中啟動(dòng)協(xié)程。

但是請(qǐng)注意,這段代碼不會(huì)顯式地等待所創(chuàng)建的兩個(gè)協(xié)程完成任務(wù)后才返回,當(dāng) fetchTwoDocs 返回時(shí),協(xié)程還正在運(yùn)行中。

所以,為了做到結(jié)構(gòu)化并發(fā)并避免泄漏的情況發(fā)生,我們想做到在諸如 fetchTwoDocs 這樣的 suspend 函數(shù)返回時(shí),它們所做的所有任務(wù)也都能結(jié)束。換個(gè)說法就是,fetchTwoDocs 返回之前,它所啟動(dòng)的所有協(xié)程也都能完成任務(wù)。

Kotlin 確保使用 coroutineScope 構(gòu)造器不會(huì)讓 fetchTwoDocs 發(fā)生泄漏,coroutinScope 會(huì)先將自身掛起,等待它內(nèi)部啟動(dòng)的所有協(xié)程完成,然后再返回。因此,只有在 coroutineScope 構(gòu)建器中啟動(dòng)的所有協(xié)程完成任務(wù)之后,fetchTwoDocs 函數(shù)才會(huì)返回。

  • coroutineScope:https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/coroutine-scope.html
  • supervisorScope:https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/supervisor-scope.html

處理一堆任務(wù)

既然我們已經(jīng)做到了追蹤一兩個(gè)協(xié)程,那么來個(gè)刺激的,追蹤一千個(gè)協(xié)程來試試!

先看看下面這個(gè)動(dòng)畫

 

 

 

這個(gè)動(dòng)畫展示了 coroutineScope 是如何追蹤一千個(gè)協(xié)程的

 

這個(gè)動(dòng)畫向我們展示了如何同時(shí)發(fā)出一千個(gè)網(wǎng)絡(luò)請(qǐng)求。當(dāng)然,在真實(shí)的 Android 開發(fā)中最好別這么做,太浪費(fèi)資源了。

這段代碼中,我們?cè)?coroutineScope 構(gòu)造器中使用 launch 啟動(dòng)了一千個(gè)協(xié)程,您可以看到這一切是如何聯(lián)系到一起的。由于我們使用的是 suspend 函數(shù),因此代碼一定使用了 CoroutineScope 創(chuàng)建了協(xié)程。我們目前對(duì)這個(gè) CoroutineScope 一無所知,它可能是viewModelScope 或者是其他地方定義的某個(gè) CoroutineScope,但不管怎樣,coroutineScope 構(gòu)造器都會(huì)使用它作為其創(chuàng)建新的 scope 的父級(jí)。

然后,在 coroutineScope 代碼塊內(nèi),launch 將會(huì)在新的 scope 中啟動(dòng)協(xié)程,隨著協(xié)程的啟動(dòng)完成,scope 會(huì)對(duì)其進(jìn)行追蹤。最后,一旦所有在 coroutineScope 內(nèi)啟動(dòng)的協(xié)程都完成后,loadLots 方法就可以輕松地返回了。

注意:scope 和協(xié)程之間的父子關(guān)系是使用 Job 對(duì)象進(jìn)行創(chuàng)建的。但是您不需要深入去了解,只要知道這一點(diǎn)就可以了。

coroutineScope 和 supervisorScope 將會(huì)等待所有的子協(xié)程都完成。

以上的重點(diǎn)是,使用 coroutineScope 和 supervisorScope 可以從任何 suspend function 來安全地啟動(dòng)協(xié)程。即使是啟動(dòng)一個(gè)新的協(xié)程,也不會(huì)出現(xiàn)泄漏,因?yàn)樵谛碌膮f(xié)程完成之前,調(diào)用方始終處于掛起狀態(tài)。

更厲害的是,coroutineScope 將會(huì)創(chuàng)建一個(gè)子 scope,所以一旦父 scope 被取消,它會(huì)將取消的消息傳遞給所有新的協(xié)程。如果調(diào)用方是 viewModelScope,這一千個(gè)協(xié)程在用戶離開界面后都會(huì)自動(dòng)被取消掉,非常整潔高效。

在繼續(xù)探討報(bào)錯(cuò) (error) 相關(guān)的問題之前,有必要花點(diǎn)時(shí)間來討論一下 supervisorScope 和 coroutineScope,它們的主要區(qū)別是當(dāng)出現(xiàn)任何一個(gè)子 scope 失敗的情況,coroutineScope 將會(huì)被取消。如果一個(gè)網(wǎng)絡(luò)請(qǐng)求失敗了,所有其他的請(qǐng)求都將被立即取消,這種需求選擇 coroutineScope。相反,如果您希望即使一個(gè)請(qǐng)求失敗了其他的請(qǐng)求也要繼續(xù),則可以使用 supervisorScope,當(dāng)一個(gè)協(xié)程失敗了,supervisorScope 是不會(huì)取消剩余子協(xié)程的。

協(xié)程失敗時(shí)發(fā)出報(bào)錯(cuò)信號(hào)

在協(xié)程中,報(bào)錯(cuò)信號(hào)是通過拋出異常來發(fā)出的,就像我們平常寫的函數(shù)一樣。來自 suspend 函數(shù)的異常將通過 resume 重新拋給調(diào)用方來處理。跟常規(guī)函數(shù)一樣,您不僅可以使用 try/catch 這樣的方式來處理錯(cuò)誤,還可以構(gòu)建抽象來按照您喜歡的方式進(jìn)行錯(cuò)誤處理。

但是,在某些情況下,協(xié)程還是有可能會(huì)弄丟獲取到的錯(cuò)誤的。

  1. val unrelatedScope = MainScope() 
  2. // 丟失錯(cuò)誤的例子 
  3. suspend fun lostError() { 
  4.    // 未使用結(jié)構(gòu)化并發(fā)的 async 
  5.     unrelatedScope.async { 
  6.         throw InAsyncNoOneCanHearYou("except") 
  7.     } 

注意:上述代碼聲明了一個(gè)無關(guān)聯(lián)協(xié)程作用域,它將不會(huì)按照結(jié)構(gòu)化并發(fā)的方式啟動(dòng)新的協(xié)程。還記得我在一開始說的結(jié)構(gòu)化并發(fā)是一系列編程語言特性和實(shí)踐指南的集合,在 suspend 函數(shù)中引入無關(guān)聯(lián)協(xié)程作用域違背了結(jié)構(gòu)化并發(fā)規(guī)則。

在這段代碼中錯(cuò)誤將會(huì)丟失,因?yàn)?async 假設(shè)您最終會(huì)調(diào)用 await 并且會(huì)重新拋出異常,然而您并沒有去調(diào)用 await,所以異常就永遠(yuǎn)在那等著被調(diào)用,那么這個(gè)錯(cuò)誤就永遠(yuǎn)不會(huì)得到處理。

結(jié)構(gòu)化并發(fā)保證當(dāng)一個(gè)協(xié)程出錯(cuò)時(shí),它的調(diào)用方或作用域會(huì)被通知到。

如果您按照結(jié)構(gòu)化并發(fā)的規(guī)范去編寫上述代碼,錯(cuò)誤就會(huì)被正確地拋給調(diào)用方處理。

  1. suspend fun foundError() { 
  2.     coroutineScope { 
  3.         async {  
  4.             throw StructuredConcurrencyWill("throw") 
  5.         } 
  6.     } 

coroutineScope 不僅會(huì)等到所有子任務(wù)都完成才會(huì)結(jié)束,當(dāng)它們出錯(cuò)時(shí)它也會(huì)得到通知。如果一個(gè)通過 coroutineScope 創(chuàng)建的協(xié)程拋出了異常,coroutineScope 會(huì)將其拋給調(diào)用方。因?yàn)槲覀冇玫氖莄oroutineScope 而不是 supervisorScope,所以當(dāng)拋出異常時(shí),它會(huì)立刻取消所有的子任務(wù)。

使用結(jié)構(gòu)化并發(fā)

在這篇文章中,我介紹了結(jié)構(gòu)化并發(fā),并展示了如何讓我們的代碼配合 Android 中的 ViewModel 來避免出現(xiàn)任務(wù)泄漏。

同樣,我還幫助您更深入去理解和使用 suspend 函數(shù),通過確保它們?cè)诤瘮?shù)返回之前完成任務(wù),或者是通過暴露異常來確保它們正確發(fā)出錯(cuò)誤信號(hào)。

如果我們使用了不符合結(jié)構(gòu)化并發(fā)的代碼,將會(huì)很容易出現(xiàn)協(xié)程泄漏,即調(diào)用方不知如何追蹤任務(wù)的情況。這種情況下,任務(wù)是無法取消的,同樣也不能保證異常會(huì)被重新拋出來。這樣會(huì)使得我們的代碼很難理解,并可能會(huì)導(dǎo)致一些難以追蹤的 bug 出現(xiàn)。

您可以通過引入一個(gè)新的不相關(guān)的 CoroutineScope (注意是大寫的 C),或者是使用 GlobalScope 創(chuàng)建的全局作用域,但是這種方式的代碼不符合結(jié)構(gòu)化并發(fā)要求的方式。

但是當(dāng)出現(xiàn)需要協(xié)程比調(diào)用方的生命周期更長(zhǎng)的情況時(shí),就可能需要考慮非結(jié)構(gòu)化并發(fā)的編碼方式了,只是這種情況比較罕見。因此,使用結(jié)構(gòu)化編程來追蹤非結(jié)構(gòu)化的協(xié)程,并進(jìn)行錯(cuò)誤處理和任務(wù)取消,將是非常不錯(cuò)的做法。

如果您之前一直未按照結(jié)構(gòu)化并發(fā)的方法編碼,一開始確實(shí)一段時(shí)間去適應(yīng)。這種結(jié)構(gòu)確實(shí)保證與 suspend 函數(shù)交互更安全,使用起來更簡(jiǎn)單。在編碼過程中,盡可能多地使用結(jié)構(gòu)化并發(fā),這樣讓代碼更易于維護(hù)和理解。

在本文的開始列舉了結(jié)構(gòu)化并發(fā)為我們解決的三個(gè)問題:

  • 取消任務(wù) —— 當(dāng)某項(xiàng)任務(wù)不再需要時(shí)取消它;
  • 追蹤任務(wù) —— 當(dāng)任務(wù)正在執(zhí)行時(shí),追蹤它;
  • 發(fā)出錯(cuò)誤信號(hào) —— 當(dāng)協(xié)程失敗時(shí),發(fā)出錯(cuò)誤信號(hào)表明有錯(cuò)誤發(fā)生。

實(shí)現(xiàn)這種結(jié)構(gòu)化并發(fā),會(huì)為我們的代碼提供一些保障:

  • 作用域取消時(shí),它內(nèi)部所有的協(xié)程也會(huì)被取消;
  • suspend 函數(shù)返回時(shí),意味著它的所有任務(wù)都已完成;
  • 協(xié)程報(bào)錯(cuò)時(shí),它所在的作用域或調(diào)用方會(huì)收到報(bào)錯(cuò)通知。

總結(jié)來說,結(jié)構(gòu)化并發(fā)讓我們的代碼更安全,更容易理解,還避免了出現(xiàn)任務(wù)泄漏的情況。

下一步

本篇文章,我們探討了如何在 Android 的 ViewModel 中啟動(dòng)協(xié)程,以及如何在代碼中運(yùn)用結(jié)構(gòu)化并發(fā),來讓我們的代碼更易于維護(hù)和理解。

在下一篇文章中,我們將探討如何在實(shí)際編碼過程中使用協(xié)程,感興趣的讀者請(qǐng)繼續(xù)關(guān)注我們的更新。

【本文是51CTO專欄機(jī)構(gòu)“谷歌開發(fā)者”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)聯(lián)系原作者(微信公眾號(hào):Google_Developers)】

戳這里,看該作者更多好文

 

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2020-04-08 09:06:34

Android 協(xié)程開發(fā)

2020-07-07 09:19:28

Android 協(xié)程開發(fā)

2014-06-24 09:41:56

Android Stu教程

2013-12-04 14:44:41

Android SDK用戶交互

2013-12-26 15:40:33

Android SDK項(xiàng)目

2013-12-04 13:27:56

Android SDK項(xiàng)目

2014-01-22 10:00:10

Android SDKAndroid開發(fā)

2021-01-26 08:37:18

MobXVueReact

2013-12-26 15:14:38

Android SDK運(yùn)行調(diào)試

2024-01-29 00:36:50

Backstage設(shè)施工具

2025-05-28 15:46:13

2013-12-26 15:47:59

Android SDK應(yīng)用程序

2013-12-04 14:29:18

Android SDK應(yīng)用程序

2013-11-27 10:12:11

2013-12-26 14:52:52

Android SDK物理設(shè)備

2021-11-26 09:40:37

EclipseIDEA開發(fā)

2016-06-20 10:20:22

Docker云計(jì)算

2013-12-04 13:51:38

Android SDK應(yīng)用程序

2013-12-04 15:11:03

Android SDK應(yīng)用程序

2014-03-16 09:21:39

Android開發(fā)Android SDK
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

国产高清在线观看| 国产探花在线免费观看| 香蕉视频亚洲一级| 中文字幕av不卡| 99久久无色码| 久久久久在线视频| 午夜视频一区| 亚洲天堂av网| 成年人性生活视频| 狠狠久久综合婷婷不卡| 国产毛片久久久久久久| 999色成人| 欧美午夜片在线免费观看| 亚洲欧美日本国产有色| 人妻视频一区二区三区| 免费高清成人在线| 91国产精品视频在线| 日本一二三区在线观看| 免费观看久久av| 精品日产卡一卡二卡麻豆| 久久久久免费精品| 国产亚av手机在线观看| 国产精品家庭影院| 久久一区二区三区av| 99久久国产热无码精品免费| 天堂精品中文字幕在线| 欧美激情精品久久久久| 国产一区二区四区| 91丝袜超薄交口足| 1234区中文字幕在线观看| 国产精品福利av| 欧美一级二级三级| 天堂网在线中文| 粉嫩嫩av羞羞动漫久久久| 国产日韩av在线播放| 国产亚洲欧美在线精品| 99精品国产一区二区青青牛奶| 美日韩精品视频免费看| 自拍偷拍第9页| 国产亚洲一卡2卡3卡4卡新区| 亚洲精品mp4| 一区二区三区四区影院| 亚洲风情在线资源| 性做久久久久久| 国产精品自拍合集| 最爽无遮挡行房视频在线| 国产精品久久久久精k8| 韩国理伦片一区二区三区在线播放| 中文字幕久久久av一区| 91激情视频在线观看| 免费成人结看片| 亚洲欧洲av一区二区| 国产艳俗歌舞表演hd| 欧美精品中文| 日韩极品精品视频免费观看| 一级国产黄色片| 美女视频亚洲色图| 日韩成人中文字幕| 亚洲国产果冻传媒av在线观看| 久久久精品国产**网站| 亚洲精品国产精品自产a区红杏吧| 久久精品aⅴ无码中文字字幕重口| 视频精品国内| 精品国产一区二区精华| 亚洲精品第二页| 欧美美女黄色| 亚洲偷熟乱区亚洲香蕉av| 欧美亚洲高清一区二区三区不卡| 国产在线无码精品| 第一av在线| 午夜免费久久看| 国产一区二区三区精彩视频| 日本免费一区二区三区四区| 欧美在线观看视频在线| 日本在线播放一区二区| 日韩成人视屏| 日韩av在线免费观看一区| 久久精品一区二区免费播放| 成人一区不卡| 欧美区二区三区| 黄色在线观看国产| 久久99国产精品久久99| 国产精品9999久久久久仙踪林| 日本亚洲欧美| 国产精品狼人久久影院观看方式| 大桥未久一区二区三区| 午夜影视一区二区三区| 韩国成人动漫| 国产精品免费看片| 激情六月天婷婷| 亚洲私拍视频| 欧美夫妻性生活| 波多野结衣有码| 欧美jizz| 91av在线精品| 亚洲综合五月天婷婷丁香| 粉嫩av一区二区三区| 日本一区二区三区四区高清视频| 18视频在线观看网站| 欧美丝袜一区二区三区| 一卡二卡三卡四卡五卡| 久久不卡国产精品一区二区 | 亚洲超碰精品一区二区| 在线免费视频a| 亚洲综合影院| 色哟哟亚洲精品一区二区| 日韩一区不卡| 国产黄色片在线免费观看| 国产日韩精品视频一区二区三区| 国产综合视频在线观看| 视频一区二区三区国产| 亚洲美女屁股眼交3| 久久久噜噜噜www成人网| 欧洲精品99毛片免费高清观看| 亚洲天堂视频在线观看| 日本天堂网在线观看| 寂寞少妇一区二区三区| 欧美大陆一区二区| 精品一性一色一乱农村| 欧美日韩国产综合久久| 18禁裸乳无遮挡啪啪无码免费| 欧美大片一区| 国产在线观看一区二区三区| 青青草超碰在线| 亚洲va国产va欧美va观看| 男生和女生一起差差差视频| 日韩成人影院| 国产成人拍精品视频午夜网站| 日韩av片在线看| 国产农村妇女毛片精品久久| 国产欧美一区二区精品仙草咪| 青青草精品视频在线| 国产在线一区不卡| 日韩最新免费不卡| 国产一区免费看| 久久久久久久久久美女| 日韩精品在线观看av| 视频一区日韩精品| 欧美老肥婆性猛交视频| 国产精选久久久| 中文字幕va一区二区三区| 国产日韩成人内射视频| 伊人春色精品| 国产成人av网| 国产精品久久久久一区二区国产| 天天影视色香欲综合网老头| 漂亮人妻被黑人久久精品| 国产精品99一区二区| 国产高清精品一区| av丝袜在线| 国产欧美日韩三区| 亚洲国产成人久久综合一区| a天堂中文字幕| 日韩黄色小视频| 日韩久久精品一区二区三区| 亚洲国产尤物| 久久精品福利视频| 99久久亚洲精品日本无码| 亚洲乱码日产精品bd| 原创真实夫妻啪啪av| 狠狠入ady亚洲精品| 高清日韩一区| 在线观看特色大片免费视频| 亚洲视频999| 亚洲天堂中文在线| 亚洲美女视频一区| 午夜av免费看| 日本vs亚洲vs韩国一区三区 | 亚洲1卡2卡3卡4卡乱码精品| 欧美午夜影院一区| 精品无码久久久久成人漫画| 在线中文字幕网站| 91欧美一区二区| 中文字幕第80页| 91精品一区二区三区综合在线爱| 91久久精品国产91久久性色tv| missav|免费高清av在线看| 日韩精品极品视频| 中文字幕有码视频| 亚洲综合色网站| 一本加勒比北条麻妃| 疯狂欧洲av久久成人av电影| 久久这里有精品视频| 日韩中文字幕观看| 欧洲一区二区三区免费视频| 神马久久精品综合| 成人va在线观看| 免费黄色一级网站| 欧美韩国一区| 免费看污久久久| 国产成年精品| 国产精品 欧美在线| 18av在线播放| 国产亚洲精品一区二区| 无码人妻一区二区三区在线视频| 不卡av免费观看| 亚洲免费av片| 精品人妻一区二区三区蜜桃 | 波多野结衣网站| 一区二区成人在线视频| 一二三四国产精品| caoporen国产精品视频| 亚洲精品在线视频播放| 久久久精品网| a级免费在线观看| 国产精品国内免费一区二区三区| 久久国产精品 国产精品| 日韩第二十一页| 全亚洲最色的网站在线观看| 色yeye免费人成网站在线观看| 一区二区在线视频| 午夜影院在线视频| 欧美日韩你懂的| 中文字幕一区二区人妻电影| 亚洲综合色噜噜狠狠| 成人黄色短视频| 久久久久久久久97黄色工厂| 欧美做受高潮中文字幕| 国内欧美日韩| 亚洲青青青在线视频| 女同性αv亚洲女同志| 看电视剧不卡顿的网站| 成人一级片网站| 极品av少妇一区二区| 中日韩在线视频| 青青草原综合久久大伊人精品| 牛人盗摄一区二区三区视频| 成功精品影院| 国产精品白丝jk白祙| 国产精品亚洲综合在线观看 | 久久艹在线视频| 永久免费在线观看视频| 国产一区二区精品丝袜| 欧美日韩免费做爰大片| 亚洲精品影视在线观看| 婷婷开心激情网| 91精品国产欧美一区二区18| 国产孕妇孕交大片孕| 欧美高清hd18日本| 97人妻精品一区二区三区软件 | 久久久久无码精品国产| 九九在线精品视频| 波多结衣在线观看| 日韩av成人高清| 亚洲精品怡红院| 男女男精品网站| 久久久久久蜜桃一区二区| 日韩电影一区二区三区| 黄色三级视频片| 日本不卡一二三区黄网| 最新天堂在线视频| 精品一区二区三区久久| 日韩a一级欧美一级| 国产成人精品免费在线| 久久久高清视频| 91在线小视频| 一级片视频免费看| 中文无字幕一区二区三区| 99自拍视频在线| 亚洲精品老司机| 麻豆一区二区三区精品视频| 福利一区视频在线观看| 午夜视频网站在线观看| 欧美精品久久一区| 亚洲精品视频专区| 日韩精品在线免费观看| av福利在线播放| 亚洲二区免费| 久久久水蜜桃| 精品国产99| 最新欧美日韩亚洲| 伊人蜜桃色噜噜激情综合| 免费高清在线观看免费| 免费高清视频精品| 国产免费无码一区二区| wwwwww.欧美系列| 成人欧美一区二区三区黑人一| 综合婷婷亚洲小说| 亚洲男人第一av| 精品视频免费在线| 亚洲AV无码成人片在线观看| 日韩福利视频在线观看| 日本中文字幕电影在线免费观看| 两个人的视频www国产精品| 超碰资源在线| 国产区亚洲区欧美区| 成人高潮a毛片免费观看网站| 蜜桃久久精品乱码一区二区 | 大陆极品少妇内射aaaaa| 日韩高清一区在线| 亚洲三级在线视频| www一区二区| 国产精品亚洲一区| 黄色动漫在线观看| 77777亚洲午夜久久多人| 久久精品国产福利| 国模精品一区二区三区| 久久精品影视| av观看免费在线| 国产电影一区二区三区| av黄色在线免费观看| 亚洲激情第一区| 综合久久中文字幕| 日韩av在线一区| 四虎影院观看视频在线观看| 国产精品免费久久久| 欧美日韩导航| 欧美极品少妇无套实战| 另类专区欧美蜜桃臀第一页| 国产伦精品一区二区三区妓女| 亚洲色图欧美偷拍| 久草热在线观看| 精品视频在线播放| 国产羞羞视频在线播放| 亚洲free嫩bbb| 久久婷婷蜜乳一本欲蜜臀| 99热成人精品热久久66| av午夜一区麻豆| 久久国产在线视频| 51精品视频一区二区三区| 岛国最新视频免费在线观看| 97视频免费在线看| 天天操夜夜操av| 国内精品伊人久久久久av影院| 中文幕无线码中文字蜜桃| 天天操天天综合网| 亚洲精品一区二区三区新线路 | 不卡一本毛片| 91|九色|视频| 欧美日本一区二区视频在线观看 | 久久人人爽人人爽人人片av高清| 91亚洲精品在看在线观看高清| 午夜视频久久久| 日韩电影免费在线看| 亚洲综合色一区| 色综合av在线| 免费黄网站在线观看| 热99精品里视频精品| 日韩av午夜| 无码人妻丰满熟妇区毛片18| 2021久久国产精品不只是精品| 国产一区二区三区影院| 亚洲精品不卡在线| 午夜久久中文| 日本在线成人一区二区| 日韩成人午夜精品| 亚洲一级黄色录像| 伊人222成人综合网| 久久久久久久电影一区| 日韩影片在线观看| 黄色一级片黄色| 成人动漫中文字幕| 天堂网av手机版| 亚洲欧美日韩精品久久| 亚洲播播91| 亚洲精品不卡| 国产在线精品免费av| 欧美日韩亚洲国产另类| 精品国产污网站| 日本а中文在线天堂| 欧美精品免费观看二区| 日韩精品久久久久久| 亚洲国产精品一区二区久久hs| 欧美精品第1页| 欧美videossex| 久久av二区| 日本色综合中文字幕| 国内毛片毛片毛片毛片毛片| 日韩欧美在线影院| 鲁鲁在线中文| 相泽南亚洲一区二区在线播放| 久久精品国产色蜜蜜麻豆| 国产黄色小视频网站| 精品国产第一区二区三区观看体验| 黄频免费在线观看| 色99中文字幕| 国产精品18久久久| 久热这里只有精品6| 主播福利视频一区| 黄色在线网站| 黑人巨大精品欧美一区二区一视频 | 国产成人综合精品三级| 日韩 欧美 中文| 中文字幕一区二区精品| 亚洲超碰在线观看| 欧美 激情 在线| 亚洲三级在线观看| 十九岁完整版在线观看好看云免费| 国产精品免费电影| 国产综合自拍| 久久久精品成人| 精品av综合导航| 日本一道高清亚洲日美韩| 无码人妻精品一区二区蜜桃百度| 91在线你懂得| 国产视频第二页| 日韩免费在线视频| 99久久精品国产亚洲精品 | www.日韩在线观看| 国产精品av在线|