協(xié)程學(xué)習(xí)筆錄

導(dǎo)入庫

    api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.0'
    api 'org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.1.0'

隨筆

GlobalScope

GlobalScope為是全局的尸执,生命周期是app的生命周期如失。
全局協(xié)程類似于守護(hù)線程.在 [GlobalScope]作用范圍內(nèi)啟動的活躍的協(xié)程, 
不會保持應(yīng)用程序的整個進(jìn)程存活. 它們的行為就象守護(hù)線程一樣.不會蓖使螅活進(jìn)程.
GlobalScope.launch 時, 我們創(chuàng)建了一個頂級的協(xié)程. 雖然它是輕量的, 但它運(yùn)行時還是會消耗一些內(nèi)存資源.
由GlobalScope啟動的協(xié)程
( GlobalScope.launch {  }/GlobalScope.async {  })
任務(wù)總是在子線程執(zhí)行

runBlocking

  runBlocking {  }
任務(wù)執(zhí)行在當(dāng)前啟動線程抗俄,并且會阻塞當(dāng)前線程
在主線程啟動則任務(wù)在主線程執(zhí)行动雹,在子線程啟動任務(wù)則在子線程執(zhí)行

Job

job.cancel() // 取消 job
job.join() // 等待 job 結(jié)束
Job.cancelAndJoin()//取消作業(yè)并暫停調(diào)用協(xié)同程序胰蝠,直到取消的作業(yè)完成
由于有些協(xié)程不會等待子協(xié)程執(zhí)行,所以可以調(diào)用子協(xié)程的join方法躲庄,
告訴父協(xié)程噪窘,請等待我執(zhí)行完畢效扫,例如:

fun main() = runBlocking {
    val job = GlobalScope.launch {
// 啟動新的協(xié)程, 并保存它的執(zhí)行任務(wù)的引用
//由于是全局協(xié)程荡短,所以runBlocking 不會等待他執(zhí)行完成
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join() // 等待, 直到子協(xié)程執(zhí)行完畢
}

fun main() =runBlocking {
            launch{//由于屬于子協(xié)程掘托,不需要手動join闪盔,runBlocking 會等待他完成
                delay(2000L)
                 println("World!") // 后打印
            }
            println("Hello,")//先打印,打印完成仍會等待launch執(zhí)行
        }

//嵌套coroutineScope/runBlocking,會自動等待子協(xié)程執(zhí)行完成听绳,再執(zhí)行后面的
fun main() =runBlocking {
            coroutineScope {//新的作用域椅挣,注意區(qū)分launch,runBlocking 會等待它執(zhí)行完成再執(zhí)行后面的代碼
                delay(200L)
                println("Hello,")//等待之后鼠证,先打印
            }
            println("World!") // 后打印量九,等待launch執(zhí)行完再執(zhí)行
        }

coroutineScope

[runBlocking] 和 [coroutineScope] 之間的主要區(qū)別是, 
[coroutineScope]在等待子協(xié)程運(yùn)行時, 不會阻塞當(dāng)前線程

coroutineScope {
                // 創(chuàng)建新的協(xié)程作用范圍
                launch {
                    delay(500L)
                    println("World!")//后打印
                }
                println("Hello,") // 先打印,打印完等待launch執(zhí)行完成之后才結(jié)束
            }

launch和async

launch和async區(qū)別
launch里面的代碼會立即執(zhí)行
async的代碼需要手動執(zhí)行(使用await())

suspend

專門修飾協(xié)程方法荠列,例如

fun main() = runBlocking {
    launch { doWorld() }
    println("Hello,")
}
// 這是你的第一個掛起函數(shù)
suspend fun doWorld() {
    delay(1000L)
    println("World!")
}

但是如果抽取出來的函數(shù)包含一個協(xié)程構(gòu)建器, 并且這個構(gòu)建器需要在當(dāng)前作用范圍上調(diào)用, 那么怎么辦? 
這種情況下, 對于被抽取出來的函數(shù)來說只有 `suspend` 修飾符是不夠的. 
有一種解決辦法是把 `doWorld` 變成 `CoroutineScope` 的擴(kuò)展函數(shù), 但這種辦法有時候并不適用, 
因為它會使得 API 難于理解. 理想的解決辦法是, 要么明確地把 `CoroutineScope` 作為一個類的域變量,
 再讓這個類包含我們抽取的函數(shù), 或者讓外層類實現(xiàn) `CoroutineScope` 接口, 于是就可以隱含的實現(xiàn)這個目的. 
最后一種辦法就是, 可以使用 [CoroutineScope(coroutineContext)], 
但這種方法從結(jié)構(gòu)上來說并不安全, 因為你不再能夠控制當(dāng)前方法運(yùn)行時所屬的作用范圍. 
只有私有 API 才能夠使用這個構(gòu)建器.

協(xié)程的取消

協(xié)程的取消是 *協(xié)作式的*. 協(xié)程的代碼必須與外接配合, 才能夠被取消.
 `kotlinx.coroutines` 庫中的所有掛起函數(shù)都是 *可取消的*. 
這些函數(shù)會檢查協(xié)程是否被取消, 并在被取消時出 [CancellationException]異常. 
但是, 如果一個協(xié)程正在進(jìn)行計算, 并且沒有檢查取消狀態(tài), 那么它是不可被取消的

//可以取消(唯一的不同就是判斷條件)
  runBlocking {
         val startTime = System.currentTimeMillis()
         val job = launch(Dispatchers.Default) {
             var nextPrintTime = startTime
             var i = 0
             repeat (1000) { // 一個執(zhí)行計算的循環(huán)戚宦,只是為了占用 CPU
                 // 每秒打印消息兩次
                 if (System.currentTimeMillis() >= nextPrintTime) {
                     println("job: I'm sleeping ${i++} ...")
                     nextPrintTime += 500L
                 }
             }
         }
         delay(1300L) // 等待一段時間
         println("main: I'm tired of waiting!")
         job.cancelAndJoin() // 取消一個作業(yè)并且等待它結(jié)束
         println("main: Now I can quit.")
     }

//無法取消(唯一的不同就是判斷條件)
  runBlocking {
         val startTime = System.currentTimeMillis()
         val job = launch(Dispatchers.Default) {
             var nextPrintTime = startTime
             var i = 0
             while (i<1000) { // 一個執(zhí)行計算的循環(huán)受楼,只是為了占用 CPU
                 // 每秒打印消息兩次
                 if (System.currentTimeMillis() >= nextPrintTime) {
                     println("job: I'm sleeping ${i++} ...")
                     nextPrintTime += 500L
                 }
             }
         }
         delay(1300L) // 等待一段時間
         println("main: I'm tired of waiting!")
         job.cancelAndJoin() // 取消一個作業(yè)并且等待它結(jié)束
         println("main: Now I can quit.")
     }

withContext

可以使用 [withContext] 函數(shù)和 [NonCancellable] 上下文,
把相應(yīng)的代碼包裝在 `withContext(NonCancellable) {...}`

withTimeout

//到達(dá)超時后自動取消
fun main() = runBlocking {
//sampleStart
    withTimeout(1300L) {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
    }
//sampleEnd
}

withTimeoutOrNull

使用 [withTimeoutOrNull]函數(shù), 它與 [withTimeout] 函數(shù)類似,
但在超時發(fā)生時, 它會返回 `null`, 而不是拋出異常:

async

在概念上,[async]就類似于 [launch]河狐。
它啟動了一個單獨的協(xié)程,這是一個輕量級的線程并與其它所有的協(xié)程一起并發(fā)的工作瑟捣。
不同之處在于 `launch` 返回一個 [Job] 并且不附帶任何結(jié)果值馋艺,
而 `async` 返回一個 [Deferred] —— 一個輕量級的非阻塞 future, 這代表了一個將會在稍后提供結(jié)果的 promise迈套。
你可以使用 `.await()` 在一個延期的值上得到它的最終結(jié)果捐祠, 但是 `Deferred` 也是一個 `Job`,
所以如果需要的話桑李,你可以取消它踱蛀。

 val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
使用了CoroutineStart.LAZY需要手動調(diào)用start(),然后再使用await()

協(xié)程調(diào)度器

Unconfined            : I'm working in thread main
Default               : I'm working in thread DefaultDispatcher-worker-1
newSingleThreadContext: I'm working in thread MyOwnThread
main runBlocking      : I'm working in thread main

當(dāng)調(diào)用 `launch { …… }` 時不傳參數(shù),它從啟動了它的 [CoroutineScope] 中承襲了上下文(以及調(diào)度器)贵白。
在這個案例中率拒,它從 `main` 線程中的 `runBlocking` 主協(xié)程承襲了上下文。

[Dispatchers.Unconfined]是一個特殊的調(diào)度器且似乎也運(yùn)行在 `main` 線程中禁荒,但實際上猬膨, 它是一種不同的機(jī)制勃痴,這會在后文中講到。
該默認(rèn)調(diào)度器,當(dāng)協(xié)程在 [GlobalScope]中啟動的時候使用衫贬, 它代表 [Dispatchers.Default]使用了共享的后臺線程池
 所以 `GlobalScope.launch { …… }` 也可以使用相同的調(diào)度器—— `launch(Dispatchers.Default) { …… }`

[newSingleThreadContext]為協(xié)程的運(yùn)行啟動了一個線程。 一個專用的線程是一種非常昂貴的資源葬毫。
 在真實的應(yīng)用程序中兩者都必須被釋放,當(dāng)不再需要的時候,使用 [close] 函數(shù)汛骂,或存儲在一個頂層變量中使它在整個應(yīng)用程序中被重用

CoroutineScope

創(chuàng)建一個新的作用域
重點,在安卓中使用這個創(chuàng)建的才不會阻塞主線程,用runBlock會阻塞主線
CoroutineScope(context: CoroutineContext): CoroutineScope
例如:CoroutineScope(Dispatchers.Main)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侥钳,一起剝皮案震驚了整個濱河市苦酱,隨后出現(xiàn)的幾起案子颂跨,更是在濱河造成了極大的恐慌尾序,老刑警劉巖携丁,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揭保,死亡現(xiàn)場離奇詭異快骗,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)藕溅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門集币,熙熙樓的掌柜王于貴愁眉苦臉地迎上來当娱,“玉大人鹦倚,你說我怎么就攤上這事∫耄” “怎么了昏滴?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵姻几,是天一觀的道長蛇捌。 經(jīng)常有香客問我回溺,道長,這世上最難降的妖魔是什么雄坪? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任飘庄,我火速辦了婚禮迂求,結(jié)果婚禮上凌盯,老公的妹妹穿的比我還像新娘县忌。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼眶痰。 笑死七婴,一個胖子當(dāng)著我的面吹牛户盯,可吹牛的內(nèi)容都是我干的足淆。 我是一名探鬼主播丹鸿,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拣帽!你這毒婦竟也來了修陡?” 一聲冷哼從身側(cè)響起拾因,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惠遏,失蹤者是張志新(化名)和其女友劉穎透绩,沒想到半個月后狸臣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡衷畦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年沮峡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蹦漠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闸度,到底是詐尸還是另有隱情,我是刑警寧澤浩峡,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站纸淮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏飒货。R本人自食惡果不足惜扣墩,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一盲泛、第九天 我趴在偏房一處隱蔽的房頂上張望蚁孔。 院中可真熱鬧站刑,春花似錦、人聲如沸修然。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愕宋。三九已至,卻和暖如春结榄,著一層夾襖步出監(jiān)牢的瞬間中贝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工臼朗, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留邻寿,地道東北人蝎土。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像绣否,于是被迫代替她去往敵國和親誊涯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

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