一學就會的協(xié)程使用——基礎篇(五)再遇取消

1. 引言

前面已經(jīng)知道了協(xié)程作用域和協(xié)程取消的真正作用了勒奇,現(xiàn)在結合著協(xié)程作用域和withContext來再次體會下協(xié)程取消的便捷预鬓。

2. 實踐代碼說明

本文關鍵代碼(按鈕的點擊事件):

viewBinding.launchBtn -> {
    "Clicked launchBtn".let {
        myLog(it)
    }
    scope.launch(Dispatchers.IO) {
        "Coroutine IO runs (from launchBtn)".let {
            myLog(it)
        }
        Thread.sleep(FIVE_SECONDS)
        "Coroutine IO runs after thread sleep".let {
            myLog(it)
        }
        withContext(Dispatchers.Main) {
            "withContext(Dispatchers.Main) lambda".let {
                myLog(it)
            }
        }
    }
}

關鍵的代碼邏輯很簡單——

啟動一個在IO線程的協(xié)程壹将,協(xié)程輸出第一行l(wèi)og——"Coroutine IO runs (from launchBtn)"奢方;

然后休眠線程5秒,輸出第二行l(wèi)og——"Coroutine IO runs after thread sleep"齿诉;

最后切換到主線程竣蹦,輸出第三行l(wèi)og——"withContext(Dispatchers.Main) lambda"顶猜。

這里所用的協(xié)程作用域跟前篇一樣,是Activity中的屬性:

private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)

生命周期onDestroy中:

override fun onDestroy() {
    super.onDestroy()
    scope.cancel()
}

另外一個按鈕痘括,點擊時取消已經(jīng)啟動的協(xié)程:

viewBinding.cancelBtn -> {
    "Clicked cancelBtn".let {
        myLog(it)
    }
    scope.coroutineContext.cancelChildren()
}

3. 實踐過程說明

在啟動協(xié)程后长窄,5秒以內(nèi)點擊取消按鈕或者退出當前頁面,可以發(fā)現(xiàn)纲菌,協(xié)程的前兩行l(wèi)og會始終輸出挠日,但是在第三行l(wèi)og卻不會輸出,不點擊取消按鈕和始終停留在當前頁面的話翰舌,第三行l(wèi)og會正常輸出嚣潜。

為什么取消后第二行l(wèi)og始終輸出,而第三行l(wèi)og不輸出了呢椅贱?懂算?

一學就會的協(xié)程使用——基礎篇(三)初遇協(xié)程取消中,提及過協(xié)程的取消是需要協(xié)作的庇麦,也就是說计技,協(xié)程的取消需要在執(zhí)行邏輯中需要有協(xié)作點!初遇篇所用的協(xié)程取消點主要是isActiveensureActive()女器,這里初看并沒有協(xié)程取消協(xié)作點酸役,為什么第三行l(wèi)og不支持了呢?

這里便是本文的重點,所有kotlinx.coroutines包下的掛起函數(shù)都是可被取消的:

所有 kotlinx.coroutines 中的掛起函數(shù)都是 可被取消的 涣澡。它們檢查協(xié)程的取消贱呐, 并在取消時拋出 CancellationException。

上述描述出自中文文檔:https://www.kotlincn.net/docs/reference/coroutines/cancellation-and-timeouts.html

withContext是kotlinx.coroutines包下的掛起函數(shù)入桂,如上描述奄薇,是可被取消的。所以協(xié)程在執(zhí)行到withContext一行時抗愁,觸發(fā)到協(xié)作點時馁蒂,如果協(xié)程已經(jīng)被取消,所以協(xié)作點生效蜘腌。

這里便是解釋了第三行l(wèi)og在取消后不再輸出的問題沫屡。進一步地,為什么第二行l(wèi)og的執(zhí)行時機也在協(xié)程取消以后撮珠,但第二行l(wèi)og始終會輸出呢沮脖?這里必須再強調(diào):

協(xié)程的取消是 協(xié)作 的。一段協(xié)程代碼必須協(xié)作才能被取消芯急。

也就是說勺届,協(xié)程代碼執(zhí)行過程中,如果沒有取消協(xié)作點娶耍,即使在協(xié)程執(zhí)行到具體代碼位置時協(xié)程已經(jīng)被取消免姿,協(xié)程仍會繼續(xù)執(zhí)行!

在第二行代碼執(zhí)行之時榕酒,沒有任何協(xié)程取消協(xié)作點胚膊,所以不管執(zhí)行第二行l(wèi)og輸出之時協(xié)程是否已經(jīng)被取消,第二行l(wèi)og始終會輸出奈应。

第三行l(wèi)og不輸出澜掩,是因為掛起函數(shù)withContext是可取消的,也就是在withContext掛起函數(shù)執(zhí)行的時候杖挣,才觸發(fā)了協(xié)程取消的協(xié)作點肩榕,進而使得協(xié)程取消!

切記惩妇,協(xié)程取消不是萬能鑰匙株汉,調(diào)用了協(xié)程的取消后,協(xié)程并不能在任意位置停止執(zhí)行歌殃,只有執(zhí)行到協(xié)作點的時候乔妈,協(xié)程的取消才會生效!

其實氓皱,想要在5秒內(nèi)點擊取消后第二行l(wèi)og也不輸出路召,也很簡單勃刨,在第二行l(wèi)og輸出前,增加協(xié)程取消的協(xié)作點股淡,即調(diào)用ensureActive()函數(shù)即可身隐!

4. 關于掛起函數(shù)的提醒

文檔中描述,kotlinx.coroutines 中的掛起函數(shù)都是可被取消的唯灵。注意限定詞贾铝,可被取消的不是掛起函數(shù),是kotlinx.coroutines 中的掛起函數(shù)埠帕。

也就是說垢揩,掛起函數(shù)本身是不提供取消功能,只不過是kotlinx.coroutines 中的掛起函數(shù)中實現(xiàn)了對協(xié)程取消的協(xié)作代碼敛瓷。這里主要強調(diào)第一個容易誤解的點:

掛起函數(shù)本身不會提供協(xié)程取消協(xié)作點叁巨,而是協(xié)程特定包下中的掛起函數(shù)內(nèi)部實現(xiàn)代碼提供了取消協(xié)作點。

事實上琐驴,上面說的可取消的掛起函數(shù)還限定了在kotlinx.coroutines 中俘种,這句話簡直就是完美且準確!

注意啊绝淡,這個包名的第一個是kotlinx,后面是有x的苍姜,Kotlin的包名中有一個跟這個很相似的牢酵,是kotlin.coroutines,人家開發(fā)文檔可沒說kotlin.coroutines下面的掛起函數(shù)是可取消的衙猪!

比如suspendCoroutine就是不帶x的包名下的函數(shù)馍乙,所以這個掛起函數(shù)并不可取消。相對地垫释,實現(xiàn)相同功能又可取消的函數(shù)為suspendCancellableCoroutine丝格,這個函數(shù)所在的包名是帶x的。

這里suspendCoroutinesuspendCancellableCoroutine兩個函數(shù)都是掛起函數(shù)棵譬,一個不可取消显蝌,一個可取消,另一方面也可以說明掛起函數(shù)并不總是支持取消協(xié)作的订咸,取消的協(xié)作本質(zhì)在掛起函數(shù)內(nèi)部執(zhí)行邏輯而與掛起函數(shù)無關曼尊。

這里,不妨再結合本文和一學就會的協(xié)程使用——基礎篇(三)初遇協(xié)程取消中的代碼脏嚷,思考一下骆撇,協(xié)程的取消需要怎樣的配合才能發(fā)揮取消的實際作用?

5. 樣例工程代碼

代碼樣例Demo父叙,見Github:https://github.com/TeaCChen/CoroutineStudy

本文示例代碼神郊,如覺奇怪或啰嗦肴裙,其實為CancelStepTwoActivity.kt中的代碼摘取主要部分說明,在demo代碼當中涌乳,為提升細節(jié)內(nèi)容蜻懦,有更加多的封裝和輸出內(nèi)容。

本文的頁面截圖示例如下:

image-5-1.png

一學就會的協(xié)程使用——基礎篇

一學就會的協(xié)程使用——基礎篇(一)協(xié)程啟動

一學就會的協(xié)程使用——基礎篇(二)線程切換

一學就會的協(xié)程使用——基礎篇(三)初遇協(xié)程取消

一學就會的協(xié)程使用——基礎篇(四)協(xié)程作用域

一學就會的協(xié)程使用——基礎篇(五)再遇協(xié)程取消(本文)

一學就會的協(xié)程使用——基礎篇(六)初識掛起

一學就會的協(xié)程使用——基礎篇(七)初識結構化

一學就會的協(xié)程使用——基礎篇(八)初識協(xié)程異常

一學就會的協(xié)程使用——基礎篇(九)異常與supervisor

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載爷怀,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者阻肩。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市运授,隨后出現(xiàn)的幾起案子烤惊,更是在濱河造成了極大的恐慌,老刑警劉巖吁朦,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柒室,死亡現(xiàn)場離奇詭異,居然都是意外死亡逗宜,警方通過查閱死者的電腦和手機雄右,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纺讲,“玉大人擂仍,你說我怎么就攤上這事“旧酰” “怎么了逢渔?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乡括。 經(jīng)常有香客問我肃廓,道長,這世上最難降的妖魔是什么诲泌? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任盲赊,我火速辦了婚禮,結果婚禮上敷扫,老公的妹妹穿的比我還像新娘哀蘑。我一直安慰自己,他們只是感情好呻澜,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布递礼。 她就那樣靜靜地躺著,像睡著了一般羹幸。 火紅的嫁衣襯著肌膚如雪脊髓。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天栅受,我揣著相機與錄音将硝,去河邊找鬼恭朗。 笑死,一個胖子當著我的面吹牛依疼,可吹牛的內(nèi)容都是我干的痰腮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼律罢,長吁一口氣:“原來是場噩夢啊……” “哼膀值!你這毒婦竟也來了?” 一聲冷哼從身側響起误辑,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤沧踏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后巾钉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翘狱,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年砰苍,在試婚紗的時候發(fā)現(xiàn)自己被綠了潦匈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡赚导,死狀恐怖茬缩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吼旧,我是刑警寧澤寒屯,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站黍少,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏处面。R本人自食惡果不足惜厂置,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望魂角。 院中可真熱鬧昵济,春花似錦、人聲如沸野揪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽斯稳。三九已至海铆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挣惰,已是汗流浹背卧斟。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工殴边, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人珍语。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓锤岸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親板乙。 傳聞我的和親對象是個殘疾皇子是偷,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容