Android開發(fā)之MVVM模式實踐(五):async/await與suspend的講解

前言

大家好,我是小益!在上章內(nèi)容中,我們簡單了解了什么是協(xié)程以及協(xié)程的基本使用,主要提到了協(xié)程的launchwithContext用法。但是launchwithContext并不適合用于需要返回結(jié)果的并發(fā)場景,在并發(fā)場景中,我們一般會使用協(xié)程的async/await。

推薦

文章將率先在公眾號「碼途有道」上發(fā)布,如果本文對你有幫助,就關(guān)注一下公眾號吧!

一、async與awiat

async單單從字面意思理解就知道其與異步有關(guān)。async也是CoroutineScope的擴展函數(shù),其源碼如下:

public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine<T>(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

可以看出,asynclaunch一樣,也會新創(chuàng)建一個新的協(xié)程,不同的是launch返回的是Job類型,而async返回的是Deferred類型(DeferredJob的子類)。我們通過個小例子來看下async如何使用,如下:

coroutineScope.launch(Dispatchers.IO) {
    val a = async{ getUserInfo() }
    val userInfo = a.await() // 獲取結(jié)果
}

另外,async同樣可以指定運行線程:

 val a = async(Dispatchers.IO){ getUserInfo() }

二、并發(fā)

在了解async/await的基本用法后,我們再來聊一下使用async/await做并發(fā),還是通過小例子來看!

1. 案例一

coroutineScope.launch(Dispatchers.IO) {
    val a1 = async{ getUserInfo() }
    val userInfo = a1.await()
    val a2 = async{ getMessage(userInfo.token) }
    val msgList = a2.await()
}

在案例一中,getUserInfo()會先執(zhí)行,getMessage()getUserInfo()執(zhí)行完畢后再執(zhí)行,是順序執(zhí)行。

2. 案例二

coroutineScope.launch(Dispatchers.IO) {
    val a1 = async{ getUserInfo() }
    val a2 = async{ getHomeInfo() }
    val userInfo = a1.await()
    val homeInfo = a2.await()
}

在案例二中,getUserInfo()getHomeInfo()是并發(fā)執(zhí)行的。這里可能有同學(xué)會疑惑,為什么不是a1.await()執(zhí)行完畢后再執(zhí)行a2.await(),這樣和案例一不就矛盾了嗎?其實await()函數(shù)有個特性,當(dāng)有await()執(zhí)行時,它不僅只執(zhí)行自己對應(yīng)的async,它會使得前面所有未執(zhí)行的async都開始執(zhí)行,此特性一定要記住。

在案例二中,a1.await()就相當(dāng)于是一根導(dǎo)火索,a1.await()的執(zhí)行使得前面沒有執(zhí)行的async{ getUserInfo() }async{ getHomeInfo() }都開始執(zhí)行,而a2.await()僅僅是為了獲取homeInfo,并未起到執(zhí)行async{ getHomeInfo() }的作用。再粗暴點的說,即使沒有val homeInfo = a2.await()這句,案例二中的getHomeInfo()也會執(zhí)行。然后我們再返回看案例一就很清晰了,案例一中是async -> await -> async -> await的方式,所以一次只會執(zhí)行一個async,是順序執(zhí)行。

三、suspend

suspend從字面意思看是掛起和暫停的意思,在協(xié)程中主要用于修飾函數(shù)。其作用也和字面意思一樣,是將函數(shù)掛起。其流程我們可以這么理解:協(xié)程在執(zhí)行時遇到了被suspend標(biāo)記的函數(shù),然后這個函數(shù)就被切換到別的線程上去執(zhí)行了。此時的代碼執(zhí)行權(quán)在這個被切換出去的函數(shù)上,自然在位于這個函數(shù)后面的協(xié)程代碼就不會得到執(zhí)行。當(dāng)這個函數(shù)執(zhí)行完畢后,協(xié)程會切換回原來的線程,代碼執(zhí)行權(quán)回歸原線程,在這個函數(shù)后面的協(xié)程代碼會被繼續(xù)執(zhí)行。

為了清晰的了解suspend,我們還是通過一個小例子來講解:

fun init() {
    coroutineScope.launch {
        val userInfo = getUserInfo()
        tv_name.text = userInfo.name
    }
}

// 請求用戶信息
suspend fun getUserInfo(): UserInfo {
    return withContext(Dispatchers.IO){
        ...
    }
}

在上述例子中,init內(nèi)部有個協(xié)程會去請求用戶信息,請求用戶信息的方法是getUserInfo(),使用了suspend修飾。當(dāng)執(zhí)行到getUserInfo()方法時,getUserInfo()的執(zhí)行會脫離當(dāng)前的主線程,轉(zhuǎn)而切換到IO線程中執(zhí)行。因為是suspend修飾的方法,當(dāng)前的代碼執(zhí)行權(quán)會在getUserInfo()方法上,后面的tv_name.text = userInfo.name會暫停執(zhí)行,直到getUserInfo()執(zhí)行完畢,代碼執(zhí)行權(quán)從IO線程回歸主線程,tv_name.text = userInfo.name繼續(xù)執(zhí)行。

其實我們?nèi)绻タ丛创a,會發(fā)現(xiàn)withContext等很多方法都帶有suspend,這也是為什么我們可以使用這些方法達(dá)到同步編碼的原因。

public suspend fun <T> withContext(
    context: CoroutineContext,
    block: suspend CoroutineScope.() -> T
): T = suspendCoroutineUninterceptedOrReturn sc@ { uCont ->
    ...
}

另外,此處特別提出兩點:

  • suspend只是作為一個標(biāo)記,提醒協(xié)程去做出相應(yīng)處理,真正的切換線程等操作都是協(xié)程自身完成的,不是被suspend修飾的函數(shù)自身的能力
  • suspend修飾的函數(shù)可以被其他持有suspend的函數(shù)調(diào)用,但是最終這些suspend的調(diào)用執(zhí)行只能在協(xié)程中進(jìn)行,不能像普通方法那樣單獨使用

四、小結(jié)

到目前為止,我們一共使用了兩章內(nèi)容來介紹協(xié)程的基本使用,下一章我們會講解在MVVM中協(xié)程的封裝使用。如果有同學(xué)對于協(xié)程基礎(chǔ)任然有疑問,可以自行查看協(xié)程的相關(guān)文檔。

五、好文推薦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容