亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Kotlin協(xié)程launch原理詳解

 更新時(shí)間:2022年08月04日 10:49:56   作者:xfhy  
這篇文章主要為大家介紹了Kotlin協(xié)程launch原理的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

launch我們經(jīng)常用,今天來(lái)看看它是什么原理。

建議: 食用本篇文章之前記得先食用Kotlin協(xié)程之createCoroutine和startCoroutine

launch使用

launch我們應(yīng)該很熟悉了,隨便舉個(gè)例子:

fun main() {
    val coroutineScope = CoroutineScope(Job())
    coroutineScope.launch {
        println("1969年 葉文潔進(jìn)入紅岸基地")
        println("1971年 紅岸基地,葉文潔第一次向太陽(yáng)發(fā)送信號(hào),但未發(fā)現(xiàn)回波")
        delay(4000L)
        println("1975年 半人馬座三星,三體世界得知地球存在")
    }
    Thread.sleep(5000L)
}

sleep(5000L)和launch內(nèi)部是在2個(gè)線程中,互不干涉

簡(jiǎn)單地使用launch配合delay輸出了幾條語(yǔ)句。為了了解它底層的實(shí)現(xiàn)原理,還是老規(guī)矩,先反編譯一下。

public final class LaunchTestKt {
    public static final void main() {
        Job unused = BuildersKt__Builders_commonKt.launch$default(CoroutineScopeKt.CoroutineScope(JobKt.Job$default((Job) null, 1, (Object) null)), (CoroutineContext) null, (CoroutineStart) null, new LaunchTestKt$main$1((Continuation<? super LaunchTestKt$main$1>) null), 3, (Object) null);
        Thread.sleep(5000);
    }
}
final class LaunchTestKt$main$1 extends SuspendLambda implements Function2<CoroutineScope, Continuation<? super Unit>, Object> {
    int label;
    LaunchTestKt$main$1(Continuation<? super LaunchTestKt$main$1> continuation) {
        super(2, continuation);
    }
    public final Continuation<Unit> create(Object obj, Continuation<?> continuation) {
        return new LaunchTestKt$main$1(continuation);
    }
    public final Object invoke(CoroutineScope coroutineScope, Continuation<? super Unit> continuation) {
        return ((LaunchTestKt$main$1) create(coroutineScope, continuation)).invokeSuspend(Unit.INSTANCE);
    }
    public final Object invokeSuspend(Object $result) {
        Object coroutine_suspended = IntrinsicsKt.getCOROUTINE_SUSPENDED();
        switch (this.label) {
            case 0:
                ResultKt.throwOnFailure($result);
                System.out.println("1969年 葉文潔進(jìn)入紅岸基地");
                System.out.println("1971年 紅岸基地,葉文潔第一次向太陽(yáng)發(fā)送信號(hào),但未發(fā)現(xiàn)回波");
                this.label = 1;
                if (DelayKt.delay(4000, this) != coroutine_suspended) {
                    break;
                } else {
                    return coroutine_suspended;
                }
            case 1:
                ResultKt.throwOnFailure($result);
                break;
            default:
                throw new IllegalStateException("call to 'resume' before 'invoke' with coroutine");
        }
        System.out.println("1975年 半人馬座三星,三體世界得知地球存在");
        return Unit.INSTANCE;
    }
}

ps:上面這段代碼是通過(guò)jadx反編譯apk的方式拿到的源碼,看起來(lái)更加人性化。具體的流程是我們用Android Studio寫(xiě)個(gè)掛起函數(shù)的demo,然后編譯成apk,然后將apk用jadx反編譯一下,拿到對(duì)應(yīng)class的反編譯Java源碼,這樣弄出來(lái)的源碼我感覺(jué)比直接通過(guò)Android Studio的Tools->Kotlin->Show Kotlin拿到的源碼稍微好看懂一些。

咦,LaunchTestKt$main$1有沒(méi)有很眼熟?這不就是前面我們分析startCoroutine原理時(shí)得到的匿名內(nèi)部類(lèi)么,簡(jiǎn)直一模一樣。這個(gè)LaunchTestKt$main$1類(lèi)對(duì)應(yīng)的是launch的Lambda塊,它本質(zhì)上是一個(gè)Continuation。

startCoroutine原理

LaunchTestKt$main$1相關(guān)的原理,在前面已經(jīng)分析過(guò)了,這里不再贅述。這里主要看一下launch是如何與這個(gè)LaunchTestKt$main$1進(jìn)行關(guān)聯(lián)的。

launch原理

launch函數(shù)如下:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    //代碼1
    val newContext = newCoroutineContext(context)
    //代碼2
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    //代碼3
    coroutine.start(start, coroutine, block)
    return coroutine
}
  • 將傳入的CoroutineContext構(gòu)造出新的context
  • 啟動(dòng)模式,判斷是否為懶加載,如果是懶加載則構(gòu)建懶加載協(xié)程對(duì)象,否則就是標(biāo)準(zhǔn)的
  • 啟動(dòng)協(xié)程

context相關(guān)的先不看,因?yàn)槲覀僤emo這里不是懶加載的所以創(chuàng)建出來(lái)的是StandaloneCoroutine,直接看一下start是怎么啟動(dòng)協(xié)程的。

private open class StandaloneCoroutine(
    parentContext: CoroutineContext,
    active: Boolean
) : AbstractCoroutine<Unit>(parentContext, initParentJob = true, active = active) {
    override fun handleJobException(exception: Throwable): Boolean {
        handleCoroutineException(context, exception)
        return true
    }
}
public abstract class AbstractCoroutine<in T>(
    parentContext: CoroutineContext,
    initParentJob: Boolean,
    active: Boolean
) : JobSupport(active), Job, Continuation<T>, CoroutineScope {
    public fun <R> start(start: CoroutineStart, receiver: R, block: suspend R.() -> T) {
        start(block, receiver, this)
    }
}

start函數(shù)是在父類(lèi)AbstractCoroutine中實(shí)現(xiàn)的,這個(gè)start函數(shù)里面又調(diào)用了一個(gè)新的start函數(shù),當(dāng)我們點(diǎn)擊這個(gè)里面的start函數(shù)想進(jìn)去看源碼時(shí)發(fā)現(xiàn),點(diǎn)不過(guò)去,點(diǎn)了之后還是在當(dāng)前位置..... ???啥情況

CoroutineStart中找invoke方法

仔細(xì)觀察發(fā)現(xiàn),start是一個(gè)CoroutineStart對(duì)象,直接使用CoroutineStart對(duì)象然后后面就接括號(hào)了,這是類(lèi)里面有定義operator invoke方法,然后Kotlin可以通過(guò)這種方式來(lái)簡(jiǎn)化調(diào)用。我們直接去CoroutineStart中找invoke方法:

public enum class CoroutineStart {
    DEFAULT,
    LAZY,
    ATOMIC,
    UNDISPATCHED;
    public operator fun <R, T> invoke(block: suspend R.() -> T, receiver: R, completion: Continuation<T>): Unit =
        when (this) {
            DEFAULT -> block.startCoroutineCancellable(receiver, completion)
            ATOMIC -> block.startCoroutine(receiver, completion)
            UNDISPATCHED -> block.startCoroutineUndispatched(receiver, completion)
            LAZY -> Unit // will start lazily
        }
    public val isLazy: Boolean get() = this === LAZY
}

CoroutineStart是個(gè)枚舉類(lèi),定義了協(xié)程的幾種啟動(dòng)方式:DEFAULT、LAZY、ATOMIC、UNDISPATCHED。在invoke函數(shù)中,根據(jù)當(dāng)前是哪種啟動(dòng)方式進(jìn)行開(kāi)啟協(xié)程。

當(dāng)如果使用ATOMIC的方式,也就是不可取消的協(xié)程,就觸發(fā)了block.startCoroutine(receiver, completion)。有沒(méi)有覺(jué)得很眼熟,它其實(shí)就是我們上節(jié)課中分析的啟動(dòng)協(xié)程的關(guān)鍵:startCoroutine。

demo中使用的是默認(rèn)的方式,也就是DEFAULT,它只不過(guò)是在ATOMIC的基礎(chǔ)上,對(duì)startCoroutine包裝了一下,使其成為可響應(yīng)取消的協(xié)程。而UNDISPATCHED的方式,也就是不分發(fā)到其他線程去執(zhí)行,而是直接在當(dāng)前線程中進(jìn)行執(zhí)行。

startCoroutineCancellable邏輯

來(lái)看下DEFAULT之后走的startCoroutineCancellable邏輯:

public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>): Unit = runSafely(completion) {
    createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))
}
public actual fun <T> (suspend () -> T).createCoroutineUnintercepted(
    completion: Continuation<T>
): Continuation<Unit> {
    val probeCompletion = probeCoroutineCreated(completion)
    return if (this is BaseContinuationImpl)
        //走這里
        create(probeCompletion)
    else
        createCoroutineFromSuspendFunction(probeCompletion) {
            (this as Function1<Continuation<T>, Any?>).invoke(it)
        }
}

這塊就是前面文章中分析的代碼了,launch就算是走完了。其本質(zhì)上是對(duì)startCoroutine()這個(gè)基礎(chǔ)API進(jìn)行了一些封裝,讓開(kāi)發(fā)者更方便使用。

小結(jié)

launch、async之類(lèi)的是Kotlin協(xié)程框架中的中間層,它們是協(xié)程構(gòu)建器。而在協(xié)程構(gòu)建器的內(nèi)部,實(shí)際上是對(duì)協(xié)程基礎(chǔ)API: createCoroutine{}startCoroutine{}的封裝。它們除了擁有啟動(dòng)協(xié)程的基礎(chǔ)能力,還支持傳入CoroutineContext(結(jié)構(gòu)化并發(fā))、CoroutineStart(啟動(dòng)模式) 等參數(shù),方便開(kāi)發(fā)者使用

以上就是Kotlin協(xié)程launch原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Kotlin協(xié)程launch的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android控制界面刷新技巧匯總

    Android控制界面刷新技巧匯總

    這篇文章主要為大家詳細(xì)介紹了Android控制界面刷新的小技巧,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Flutter 實(shí)現(xiàn)虎牙/斗魚(yú) 彈幕功能

    Flutter 實(shí)現(xiàn)虎牙/斗魚(yú) 彈幕功能

    這篇文章主要介紹了Flutter 實(shí)現(xiàn)虎牙/斗魚(yú) 彈幕功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Android 4.4以上

    Android 4.4以上"沉浸式"狀態(tài)欄效果的實(shí)現(xiàn)方法

    Android與ios效果互仿早已不是什么稀奇的事,我猜大概這個(gè)效果來(lái)自ios吧,有爭(zhēng)議說(shuō)這種效果不能叫做沉浸式,叫透明狀態(tài)欄更合適,我也感覺(jué)這和沉浸式的含義不太一致。但是大家都這么叫了,那就這樣唄。下面來(lái)一起看看關(guān)于Android 4.4以上"沉浸式"效果的實(shí)現(xiàn)方法。
    2016-09-09
  • Android編程連接MongoDB及增刪改查等基本操作示例

    Android編程連接MongoDB及增刪改查等基本操作示例

    這篇文章主要介紹了Android編程連接MongoDB及增刪改查等基本操作,簡(jiǎn)單介紹了MongoDB功能、概念、使用方法及Android操作MongoDB數(shù)據(jù)庫(kù)的基本技巧,需要的朋友可以參考下
    2017-07-07
  • Android自定義個(gè)性化的Dialog示例

    Android自定義個(gè)性化的Dialog示例

    這篇文章主要介紹了Android自定義個(gè)性化的Dialog,結(jié)合實(shí)例形式分析了自定義Dialog的功能、樣式、布局等相關(guān)操作技巧,需要的朋友可以參考下
    2017-02-02
  • 詳解android環(huán)境下的即時(shí)通訊

    詳解android環(huán)境下的即時(shí)通訊

    這篇文章主要介紹了詳解android環(huán)境下的即時(shí)通訊,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2016-12-12
  • Android實(shí)現(xiàn)Reveal圓形Activity轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的完整步驟

    Android實(shí)現(xiàn)Reveal圓形Activity轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的完整步驟

    這篇文章主要給大家介紹了關(guān)于Android Reveal圓形Activity轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的實(shí)現(xiàn)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Android中修改設(shè)備權(quán)限的方法

    Android中修改設(shè)備權(quán)限的方法

    這篇文章主要介紹了Android中修改設(shè)備權(quán)限的方法,涉及Android源碼中設(shè)備權(quán)限的修改技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • Android圖片三級(jí)緩存的原理及其實(shí)現(xiàn)

    Android圖片三級(jí)緩存的原理及其實(shí)現(xiàn)

    本篇文章主要介紹了Android圖片三級(jí)緩存的原理及其實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • android如何獲取聯(lián)系人所有信息

    android如何獲取聯(lián)系人所有信息

    這篇文章主要為大家詳細(xì)介紹了android如何獲取聯(lián)系人所有信息,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07

最新評(píng)論