kotlin協(xié)程suspend配合retrofit的線程切換的坑

1、先看一下suspend單獨(dú)使用時(shí)候的線程切換情況,以便于更清晰的理解suspend:


也可以完全不要suspendGetImage方法,直接剪切到launch里,無警告绒窑;如果你保留上述代碼風(fēng)格,就是用個(gè)單獨(dú)的方法舔亭。如果去掉 suspend 修飾符些膨,又或者suspend fun里沒有withContext(或其他3個(gè)協(xié)程方法)就會(huì)警告報(bào)錯(cuò);上述的代碼钦铺,并沒有監(jiān)聽Ac和Fr的生命周期订雾,想監(jiān)聽的話,用lifecycleScope.launch矛洞;

以上代碼可以看出來洼哎,一切正常,也可以很好的理解suspend掛起到底是怎么進(jìn)行線程切換的沼本,但是如果這里的代碼放到ViewModel里卻出現(xiàn)了線程無法切換的情況

class NotificationsViewModel : ViewModel() {

Log.e("dz", if(Looper.getMainLooper() == Looper.myLooper()) "主線程pre" else "子線程pre")

GlobalScope.launch {

? ? ? ? ? ? withContext(Dispatchers.IO){

? ? ? ? ? ? ? ? Log.e("dz",if(Looper.getMainLooper() ==Looper.myLooper())"主線程suspend-start" else "子線程suspend-start")

????????????????Thread.sleep(3000L);

????????????????????Log.e("dz",if(Looper.getMainLooper() ==Looper.myLooper())"主線程suspend-end" else "子線程suspend-end")

? ? ? ? ? ? }

? ? ? ? ? ? Log.e("dz",if (Looper.myLooper() ==Looper.getMainLooper())"主線程" else "子線程");


以上代碼輸出:

2021-03-16 15:57:26.377 15976-15976/com.dq.qkotlin E/dz: 主線程pre

2021-03-16 15:57:26.416 15976-16523/com.dq.qkotlin E/dz: 子線程suspend-start

2021-03-16 15:57:29.417 15976-16523/com.dq.qkotlin E/dz: 子線程suspend-end

2021-03-16 15:57:29.419 15976-16523/com.dq.qkotlin E/dz: 子線程

最大的問題就在于最后一行 居然沒想Activity一樣正池停回到主線程,但是如果把GlobalScope修改為viewModelScope抽兆,那么一切正常识补,最后一句打印”主線程“

說明了ViewModel里一定不能用GlobalScope,而是要用viewModelScope

2辫红、采用以上suspend+retrofit方式請(qǐng)求網(wǎng)絡(luò)凭涂,如果網(wǎng)絡(luò)錯(cuò)誤,會(huì)直接崩潰!


ViewModel.kt
retrofit接口.kt

如果什么都不處理贴妻,ViewModel.kt的第39行代碼會(huì)直接崩潰切油,壓根就無法打印41行的Log

3、delay 和 sleep的區(qū)別

下面的代碼名惩,連續(xù)點(diǎn)擊不會(huì)卡死主線程澎胡,無論是用delay還是sleep都不會(huì)卡死,但是選擇delay還是sleep會(huì)影響用哪個(gè)子線程

這也是最常用的協(xié)程方式

```java

requireView().findViewById<TextView>(R.id.mainScope).setOnClickListener{v->

???// 第一步 進(jìn)入這里,main是主線程

???mainScope.launch(){

???????println("mainScope start:${Thread.currentThread().name}")

???????// 第三步 進(jìn)入這里攻谁,main是主線程稚伍。也就是說:這里已經(jīng)有post(runable)的感覺了

???????withContext(Dispatchers.IO){

???????????println("mainScope -> withContext coroutine1:${Thread.currentThread().name}")

???????????// 第四步 進(jìn)入這里,DefaultDispatcher-worker-2是子線程巢株,這里可能是worker-2槐瑞,也可能是worker-3熙涤,說明是線程池

???????????delay(10000)

???????????println("mainScope -> withContext coroutine2:${Thread.currentThread().name}")

???????????// 第五步阁苞,10秒后 進(jìn)入這里,DefaultDispatcher-worker-2是子線程祠挫,這里要么是worker-3那槽,要么是wworker-2。所以這里可能和上面第四步并不是一條線程等舔。

?? ??? ?? ? //注意1:即便你在上面10秒內(nèi)調(diào)用了?mainScope.cancel()骚灸,這里的第五步的代碼還是會(huì)走,只是下面第六步的代碼不走了

?? ??? ?? ? //注意2:如果上面的?delay(10000)?換成了?sleep(10000) ,那么第四步和第五步就是同一條線程

???????}

???????println("mainScope ends:${Thread.currentThread().name}")

???????// 第六步慌植,10秒后 進(jìn)入這里甚牲,main是主線程

???}

???println("mainScope outside end:${Thread.currentThread().name}")

???// 第二步 進(jìn)入這里,main是主線程

}

```

把上面的?Dispatchers.IO 改成Dispatchers.Main蝶柿,代碼執(zhí)行流程是一樣的丈钙,但是所有都是在主線程里。

神奇的是交汤,雖然代碼都在主線程里雏赦,但是只要用delay做延時(shí),就不會(huì)卡死主線程芙扎。

delay也是協(xié)程里的方法

```java

requireView().findViewById<TextView>(R.id.mainScope).setOnClickListener{v->

???// 第一步 進(jìn)入這里星岗,main是主線程

???mainScope.launch(){

???????println("mainScope start:${Thread.currentThread().name}")

???????// 第三步 進(jìn)入這里,main是主線程戒洼。也就是說:這里已經(jīng)有post(runable)的感覺了

???????withContext(Dispatchers.Main){

???????????println("mainScope -> withContext coroutine1:${Thread.currentThread().name}")

???????????// 第四步 進(jìn)入這里俏橘,main是主線程

???????????delay(10000)//如果這里改成sleep(10000),那么會(huì)卡死主線程

???????????println("mainScope -> withContext coroutine2:${Thread.currentThread().name}")

???????????// 第五步圈浇,10秒后 進(jìn)入這里敷矫,main是主線程

???????}

???????println("mainScope ends:${Thread.currentThread().name}")

???????// 第六步,10秒后 進(jìn)入這里汉额,main是主線程

???}

???println("mainScope outside end:${Thread.currentThread().name}")

???// 第二步 進(jìn)入這里曹仗,main是主線程

}

```

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蠕搜,隨后出現(xiàn)的幾起案子怎茫,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件轨蛤,死亡現(xiàn)場(chǎng)離奇詭異蜜宪,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祥山,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門圃验,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缝呕,你說我怎么就攤上這事澳窑。” “怎么了供常?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵摊聋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我栈暇,道長(zhǎng)麻裁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任源祈,我火速辦了婚禮煎源,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘香缺。我一直安慰自己手销,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布赫悄。 她就那樣靜靜地躺著原献,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埂淮。 梳的紋絲不亂的頭發(fā)上姑隅,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音倔撞,去河邊找鬼讲仰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛痪蝇,可吹牛的內(nèi)容都是我干的鄙陡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼躏啰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼趁矾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起给僵,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤毫捣,失蹤者是張志新(化名)和其女友劉穎详拙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔓同,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饶辙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斑粱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片弃揽。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖则北,靈堂內(nèi)的尸體忽然破棺而出矿微,到底是詐尸還是另有隱情,我是刑警寧澤咒锻,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布冷冗,位于F島的核電站守屉,受9級(jí)特大地震影響惑艇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拇泛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一滨巴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧俺叭,春花似錦恭取、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至裕照,卻和暖如春攒发,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晋南。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工惠猿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人负间。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓偶妖,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親政溃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子趾访,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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