Android 開發(fā)進階:Kotlin Coroutines 使用詳解

還記得第一次聽到 Coroutines 的時候,納悶了一下皱坛,口瑞停编曼,這是什么新的番號招式(誤),之后其實也沒有多在意了剩辟,好一段時間掐场,因為一個檔案的 I/O 會把 UI Thread 卡住,必須要用異步程序去處理贩猎,寫 Handler Thread 可以避免熊户,這也是最基礎的方式,缺點也很明顯某些時候還是避不掉融欧,寫 RX 又總覺得微妙感覺有點殺雞用牛刀的感覺敏弃,后來看了一下決定用 Coroutines,于是有了本篇文章噪馏。

image.png

是什么問題要解決麦到?

functionA()
functionB()
functionC()

普通情況下,執(zhí)行的順序會是很直白的 functionA() -> functionB() -> functionC()欠肾。

如果只有一個 thread 瓶颠,這樣很順暢沒問題。

但假如這是一個跑在 main thread 上刺桃,而 ·function A· 是需要另一個 thread 的處理結果粹淋,而該結果是需要該 thread 耗費長時間作業(yè)才可以獲得的。這邊姑且稱為 IO thread 好了。那不就意味著 function A 得等到 IO thread 處理結束并告知結果才能繼續(xù)執(zhí)行 function A 乃至 function B 之后才是 function C 呢桃移?

那在等待 function A 的時候 main thread 啥事都不能做屋匕,只能 idle 在那邊動也不動。

這如果是在 Android main thread 上借杰,這樣的行為會讓畫面 freeze 过吻,時間稍微長一點就會 ANR 被 OS 當作壞掉進行異常排除了。

其實這個異步問題解決方案很多蔗衡,諸如自己寫一個 callback 纤虽,或者自干 Handler thread 去控管或者是用 RX ,去訂閱之類绞惦。某些時候顯得不直觀逼纸,或者使用起來麻煩,總有種殺雞何需使用牛刀的感覺济蝉。

那有沒有可能杰刽?我就寫成上面那樣,但是當 function A 在等待 IO thread 時堆生,讓 main thread 去做其他的事情专缠,等到 IO thread 結束耗時處理后,再回來繼續(xù)執(zhí)行 function A淑仆,function Bfunction C 呢哥力?

是的蔗怠,可以,這個解決方案便是 Coroutine 吩跋。

Coroutines 到底是什么寞射?

Coroutines ,這個單字會被標成錯字锌钮,理由是他其實是兩個單字合并而成的桥温,分別是 cooperation + routine, cooperation 意指合作梁丘,routine 意指例行作業(yè)侵浸、慣例,照這里直接翻譯就會是合作式例行作業(yè)氛谜。

想到輝夜姬讓人想告白提到了慣例行為掏觉,也是念作 routine

那我們看到的翻譯多半會是協程、協作程序…這樣講沒啥前后感值漫,誰協助程序澳腹?協助啥程序? 總之就是滿頭的問號。

這里 routine 指得是程序中被呼叫的 function酱塔、method 沥邻,也就是說,我們將 function 羊娃、method 協同其他更多的 function谋国、method 共同作業(yè)這件事情稱為 Coroutines

協同作業(yè)聽起來還是很抽象迁沫,具體協同什么呢芦瘾?

這便是 Coroutines 最典型的特色,允許 method 被暫停( suspended)執(zhí)行之后再回復(resumed)執(zhí)行集畅,而暫停執(zhí)行的 method 狀態(tài)允許被保留近弟,復原后再以暫停時的狀態(tài)繼續(xù)執(zhí)行。

image.png

換句話說挺智,就是我在 main thread 執(zhí)行到 function A 需要等 IO thread 耗時處理的結果祷愉,那我先暫停 function A, 協調讓出 main thread 讓 main thread 去執(zhí)行其他的事情赦颇,等到 IO thread 的耗時處理結束后得到結果后再回復 function A 繼續(xù)執(zhí)行二鳄,已得到我要的結果,這便是 Coroutines 的概念媒怯,這聽起來不是很簡單了呢订讼?

事實上這個概念早在 1964 年就已經被提出了,而很多語言也都有這樣的概念扇苞,只是 Android 上頭類似的東西一直沒有被積極推廣欺殿,直到 Kotlin 成為官方語言后,Coroutines 以 Support Library 的形式被推廣才又在 Android 業(yè)界流行起來鳖敷。

Kotlin Coroutines

首先脖苏,因為 Kotlin 的 Coroutine 并沒有包含在原有包裝中,而是以 Support Library 的形式提供開發(fā)者使用定踱,所以需要另外導入該 Library棍潘。

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'

這里選用這個版本進行演示,實際中可以根據自己的需要修改版本崖媚。

那因為是在 Android 上使用的亦歉, Android 上頭的 main thread 跟普通 java 有點不一樣,所以還需要另一個 implementation至扰,不然會報錯鳍徽。

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'

導入之后就可以開始使用了。

一個簡單的開始

這邊我想做的是畫面上有一個會倒數的 Text 敢课,用 Coroutines 可以簡單地做到

class CoroutineActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_coroutine)
        GlobalScope.launch(Dispatchers.Main) {

            for (i in 10 downTo 1) { 
                textView.text = "count down $i ..." // update text
                delay(1000) 
            }
            textView.text = "Done!"
        }
    }

}

那跑起來結果就像這樣:


image.png

這樣如果要 Thread 有相同的結果可以寫成這樣:

Thread {
    for (i in 10 downTo 1) {
        Thread.sleep(1000)
        runOnUiThread {
            textView.text = "count down $i ..." 
        }
    }
    runOnUiThread {
        textView.text = "Done!"
    }


}.start()

這樣會有什么問題就是另一個故事了阶祭,至少現在這樣不會馬上出現 Exception (最常見的就是使用者離開畫面沒多久就出現一個 Exception)绷杜,不過也并不是說用 Coroutines 就不會發(fā)生這些問題,記得這些做法沒有什么優(yōu)劣濒募,差別在都選擇就是了鞭盟。

說回 Coroutines ,那跟 Thread 一樣瑰剃,某些時候我們會想要臨時把它停住齿诉,那 GlobalScope.launch 會回傳一個 Job class 的玩意

val job: Job = GlobalScope.launch(Dispatchers.Main) {
    // launch coroutine in the main thread
    for (i in 10 downTo 1) { // countdown from 10 to 1
        textView.text = "count down $i ..." // update text
        delay(1000) // wait half a second
    }
    textView.text = "Done!"
}

想要把它停住的話就用 cancel 即可

job.cancel()
Scope
GlobalScope 是什么玩意?

Scope 指得是范圍晌姚,Coroutines 可以作用的范圍粤剧。在 Main thread 上或是 IO thread 上,又或者希望開更多的 Worker thread挥唠,然后是可以在某個控制流(e.g Activity 的生命周期)中可被控制的抵恋。

原則上,在 Kotlin 里頭使用任何標記 suspend 的 method(后面會提)都會在 Scope 里面宝磨,這樣才可以控制 Coroutines 的行進與存活與否弧关。

那這邊舉的例子, GlobalScope 繼承自 CoroutineScope唤锉。它是 CoroutineScope 的一個實作世囊,它的概念就是最高層級的 Coroutines ,它的作用的范圍伴隨著 Application 的生命周期窿祥,那其實他的概念與 Dispatch.Unconfined 相同(待會會提到)株憾,用他其實可以避免 Coroutines 被過早結束,但也要記得是壁肋,這個用法類似直接呼叫靜態(tài)函數号胚,需要注意。

那如果直接實作 CoroutineScope 呢?

class CoroutineActivity : AppCompatActivity(), CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = TODO("not implemented")
//...ignore
}

那會要求實作一個 CoroutineContext 浸遗,這是什么玩意?指的就是 Coroutines 作用的情景箱亿,這邊可以指定他是在 Main thread 上或者就直接弄一個 Job 給他:

class CoroutineActivity : AppCompatActivity(), CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = job

    private val job = Job()
//...ignore
}

這樣 launch 的時候就會使用這個 Job 來操作了跛锌,如果沒有特別定義,那這個 Job 就是跑在 Worker thread 上了届惋,用它更新 UI 會出現 Exception 髓帽,這方面可以依據自己的需求去做調整。

不過更多時候我會希望他能夠跑在 Main Thread 上脑豹,Koltinx Coroutine 有提供 CoroutineScope 的實作 - MainScrope

還有 58% 的精彩內容
?著作權歸作者所有,轉載或內容合作請聯系作者
支付 ¥7.99 繼續(xù)閱讀
  • 序言:七十年代末郑藏,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子瘩欺,更是在濱河造成了極大的恐慌必盖,老刑警劉巖拌牲,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異歌粥,居然都是意外死亡塌忽,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門失驶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來土居,“玉大人,你說我怎么就攤上這事嬉探〔烈” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵涩堤,是天一觀的道長眷蜓。 經常有香客問我,道長定躏,這世上最難降的妖魔是什么账磺? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮痊远,結果婚禮上垮抗,老公的妹妹穿的比我還像新娘。我一直安慰自己碧聪,他們只是感情好冒版,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逞姿,像睡著了一般辞嗡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滞造,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天续室,我揣著相機與錄音谒养,去河邊找鬼挺狰。 笑死,一個胖子當著我的面吹牛买窟,可吹牛的內容都是我干的丰泊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼始绍,長吁一口氣:“原來是場噩夢啊……” “哼瞳购!你這毒婦竟也來了?” 一聲冷哼從身側響起亏推,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤学赛,失蹤者是張志新(化名)和其女友劉穎年堆,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體罢屈,經...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡嘀韧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了缠捌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锄贷。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖曼月,靈堂內的尸體忽然破棺而出谊却,到底是詐尸還是另有隱情,我是刑警寧澤哑芹,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布炎辨,位于F島的核電站,受9級特大地震影響聪姿,放射性物質發(fā)生泄漏碴萧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一末购、第九天 我趴在偏房一處隱蔽的房頂上張望破喻。 院中可真熱鬧,春花似錦盟榴、人聲如沸曹质。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羽德。三九已至,卻和暖如春迅办,著一層夾襖步出監(jiān)牢的瞬間宅静,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工站欺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坏为,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓镊绪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親洒忧。 傳聞我的和親對象是個殘疾皇子蝴韭,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內容