最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Kotlin協(xié)程Context應(yīng)用使用示例詳解

 更新時間:2022年12月08日 09:32:08   作者:無糖可樂愛好者  
這篇文章主要為大家介紹了Kotlin協(xié)程Context應(yīng)用使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

1.Context的應(yīng)用

Context在啟動協(xié)程模式中就已經(jīng)遇到過叫CoroutineContext,它的意思就是協(xié)程上下文,線程的切換離不開它。

在啟動協(xié)程模式中也說明過為什么不用傳遞Context,因為它有一個默認值EmptyCoroutineContext,需要注意的是這個Context是不可以切換線程的因為它是一個空的上下文對象,如果有這個需求就需要傳入具體的Context,例如Dispatchers.IO

//launch
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
//runBlocking
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {
}
//async
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
}

當傳入Dispatchers.IO時執(zhí)行的線程有什么變化呢?

fun main() = runBlocking {
    val user = contextTest()
    logX(user)
}
suspend fun contextTest(): String {
    logX("Start Context")
    withContext(Dispatchers.IO) {
        logX("Loading Context.")
        delay(1000L)
    }
    logX("After Context.")
    return "End Context"
}
fun logX(any: Any?) {
    println(
        """
================================
$any 
Thread:${Thread.currentThread().name}
================================
""".trimIndent()
    )
}
//輸出結(jié)果:
//================================
//Start Context 
//Thread:main @coroutine#1
//================================
//================================
//Loading Context. 
//Thread:DefaultDispatcher-worker-1 @coroutine#1
//================================
//================================
//After Context. 
//Thread:main @coroutine#1
//================================
//================================
//End Context 
//Thread:main @coroutine#1
//================================

從輸出結(jié)果可以得出一個結(jié)論:默認是運行在main線程中當傳入Dispatchers.IO之后就會進入到IO線程執(zhí)行,然后在IO線程執(zhí)行完畢后又回到了main線程,那么除了這兩個線程之外是否還有其他線程呢?答案是有,除了這兩個之外還有2個:

public actual object Dispatchers {
    /**
     * 用于CPU密集型任務(wù)的線程池,一般來說它內(nèi)部的線程個數(shù)是與機器 CPU 核心數(shù)量保持一致的
     * 不過它有一個最小限制2,
     */
    public actual val Default: CoroutineDispatcher = DefaultScheduler
    /**
     * 主線程,在Android中才可以使用,主要用于UI的繪制,在普通JVM上無法使用
     */
    public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
    /**
     * 不局限于任何特定線程,會根據(jù)運行時的上下文環(huán)境決定
     */
    public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined
    /**
     * 用于執(zhí)行IO密集型任務(wù)的線程池,它的數(shù)量會多一些,默認最大線程數(shù)量為64個
     * 具體的線程數(shù)量可以通過kotlinx.coroutines.io.parallelism配置
     * 它會和Default共享線程,當Default還有其他空閑線程時是可以被IO線程池復(fù)用。
     */
    public val IO: CoroutineDispatcher = DefaultIoScheduler
}

除了上述幾個Dispatcher之外還可以自定義Dispatcher

fun main() = runBlocking {
    val user = contextTest()
    logX(user)
}
suspend fun contextTest(): String {
    logX("Start Context")
    //使用自定義的dispatcher
    //				↓
    withContext(myDispatcher) {
        logX("Loading Context.")
        delay(100L)
    }
    logX("After Context.")
    return "End Context"
}
val myDispatcher = Executors.newSingleThreadExecutor {
    Thread(it, "myDispatcher").apply { isDaemon = true }
}.asCoroutineDispatcher()
//輸出結(jié)果
//================================
//Start Context 
//Thread:main @coroutine#1
//================================
//================================
//Loading Context. 
//Thread:myDispatcher @coroutine#1
//================================
//================================
//After Context. 
//Thread:main @coroutine#1
//================================
//================================
//End Context 
//Thread:main @coroutine#1
//================================

通過 asCoroutineDispatcher() 這個擴展函數(shù),創(chuàng)建了一個 Dispatcher。從這里也能看到,Dispatcher 的本質(zhì)仍然還是線程。那么可以得出一個結(jié)論:協(xié)程是運行在線程之上的。

前面還有一個線程Unconfined,它是一個特殊的線程,沒有指定可運行在哪里,但是這個使用時需要謹慎甚至最好不用,通過下面的的代碼對比一下:

//不設(shè)置執(zhí)行線程
fun main() = runBlocking {
    logX("Start launch.")
    launch {
        logX("Start Delay launch.")
        delay(1000L)
        logX("End Delay launch.")
    }
    logX("End launch")
}
//輸出結(jié)果
//================================
//Start launch. 
//Thread:main @coroutine#1
//================================
//================================
//End launch 
//Thread:main @coroutine#1
//================================
//================================
//Start Delay launch. 
//Thread:main @coroutine#2
//================================
//================================
//End Delay launch. 
//Thread:main @coroutine#2
//================================
//設(shè)置執(zhí)行線程
fun main() = runBlocking {
    logX("Start launch.")
//				變化在這里
//					↓
    launch(Dispatchers.Unconfined) {
        logX("Start Delay launch.")
        delay(1000L)
        logX("End Delay launch.")
    }
    logX("End launch")
}
//輸出結(jié)果
//================================
//Start launch. 
//Thread:main @coroutine#1
//================================
//================================
//Start Delay launch. 
//Thread:main @coroutine#2
//================================
//================================
//End launch 
//Thread:main @coroutine#1
//================================
//================================
//End Delay launch. 
//Thread:kotlinx.coroutines.DefaultExecutor @coroutine#2
//================================

經(jīng)過對比可以發(fā)現(xiàn)加入Dispatchers.Unconfined會導(dǎo)致代碼的運行順序被修改,這種錯誤的產(chǎn)生一定會對項目調(diào)試造成非常大的影響,而且Dispatchers.Unconfined的定義初衷也不是為了修改代碼的執(zhí)行順序。

2.萬物皆有 Context

在Kotlin協(xié)程中,但凡是重要的概念都直接或間接的與CoroutineContext有關(guān)系,例如Job、Dispatcher、CoroutineExceptionHandler、CoroutineScope

1.CoroutineScope

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
/**
 * CoroutineScope的作用域就是把CoroutineContext做了一層封裝,核心實現(xiàn)均來自于CoroutineContext
 */
public interface CoroutineScope {
    /**
     *  此作用域的上下文。上下文被作用域封裝,并用于實現(xiàn)作為作用域擴展的協(xié)程構(gòu)建器
     */
    public val coroutineContext: CoroutineContext
}

CoroutineScope的源碼注釋寫的很清楚,核心實現(xiàn)在于CoroutineContext,CoroutineScope只是做了封裝而已,然后就可以批量的控制協(xié)程了,例如下面的代碼實現(xiàn):

fun main() = runBlocking {
    val scope = CoroutineScope(Job())
    scope.launch {
        logX("launch 1")
    }
    scope.launch {
        logX("launch 2")
    }
    scope.launch {
        logX("launch 3")
    }
    scope.launch {
        logX("launch 4")
    }
    delay(500L)
    scope.cancel()
    delay(1000L)
}

2.Job

//Job#Job
public interface Job : CoroutineContext.Element {
}
//CoroutineContext#Element
public interface CoroutineContext {
    /**
     * 從該上下文返回具有給定鍵的元素,或返回null
     */
    public operator fun <E : Element> get(key: Key<E>): E?
    /**
     * 從初始值開始累積此上下文的條目,并從左到右對當前累加器值和此上下文的每個元素應(yīng)用操作。
     */
    public fun <R> fold(initial: R, operation: (R, Element) -> R): R
    /**
     * 返回包含該上下文和其他上下文元素的上下文。
     * 刪除這個上下文中與另一個上下文中具有相同鍵的元素。
     */
    public operator fun plus(context: CoroutineContext): CoroutineContext {}
    /**
     * 返回包含此上下文中的元素的上下文,但不包含具有指定鍵的元素。
     */
    public fun minusKey(key: Key<*>): CoroutineContext
    /**
     * CoroutineContext元素的鍵
     */
    public interface Key<E : Element>
    /**
     * CoroutineContext的一個元素。協(xié)程上下文的一個元素本身就是一個單例上下文。
     */
    public interface Element : CoroutineContext {
    }
}

Job實現(xiàn)了CoroutineContext.Element,CoroutineContext.Element又實現(xiàn)了CoroutineContext那么就可以認為Job間接實現(xiàn)了CoroutineContext,所以可以認定Job就是一個CoroutineContext。

所以在定義Job時下面兩種定義方式都可以:

val job: CoroutineContext = Job()
val job: Job = Job()

3.Dispatcher

public actual object Dispatchers {
    public actual val Default: CoroutineDispatcher = DefaultScheduler 
    public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher 
    public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined 
    public val IO: CoroutineDispatcher = DefaultIoScheduler 
    public fun shutdown() { }
}
public abstract class CoroutineDispatcher :
    AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {}
public interface ContinuationInterceptor : CoroutineContext.Element {

Dispatcher中的每一個線程繼承自CoroutineDispatcher,CoroutineDispatcher實現(xiàn)了ContinuationInterceptor接口,ContinuationInterceptor又實現(xiàn)了CoroutineContext接口,由此就可以知道DispatcherCoroutineContext是如何產(chǎn)生關(guān)聯(lián)的了,或者說Dispatcher就是CortinueContext。

4.CoroutineExceptionHandler

/**
 * 協(xié)程上下文中一個可選的元素,用于處理未捕獲的異常
 */
public interface CoroutineExceptionHandler : CoroutineContext.Element {
    /**
     * 
     */
    public companion object Key : CoroutineContext.Key<CoroutineExceptionHandler>
    /**
     * 處理給定上下文中未捕獲的異常。如果協(xié)程有未捕獲的異常,則調(diào)用它。
     */
    public fun handleException(context: CoroutineContext, exception: Throwable)
}

CoroutineExceptionHandler主要用來處理協(xié)程中未捕獲的異常,未捕獲的異常只能來自根協(xié)程,子協(xié)程未捕獲的異常會委托給它們的父協(xié)程,父協(xié)程也委托給父協(xié)程,以此類推,直到根協(xié)程。所以安裝在它們上下文中的CoroutineExceptionHandler永遠不會被使用。

以上就是Kotlin協(xié)程Context應(yīng)用使用示例詳解的詳細內(nèi)容,更多關(guān)于Kotlin協(xié)程Context應(yīng)用的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android中AutoCompleteTextView自動提示

    Android中AutoCompleteTextView自動提示

    這篇文章主要為大家詳細介紹了Android中AutoCompleteTextView自動提示的實現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • android視頻播放簡單實現(xiàn)示例(VideoView&MediaPlayer)

    android視頻播放簡單實現(xiàn)示例(VideoView&MediaPlayer)

    本篇文章主要介紹了android視頻播放簡單實現(xiàn)示例(VideoView&MediaPlayer),具有一定的參考價值,有興趣的可以了解一下
    2017-08-08
  • 搭建簡易藍牙定位系統(tǒng)的實現(xiàn)方法

    搭建簡易藍牙定位系統(tǒng)的實現(xiàn)方法

    下面小編就為大家?guī)硪黄罱ê喴姿{牙定位系統(tǒng)的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • Android編程實現(xiàn)自定義控件的方法示例

    Android編程實現(xiàn)自定義控件的方法示例

    這篇文章主要介紹了Android編程實現(xiàn)自定義控件的方法,結(jié)合實例形式分析了Android自定義控件的布局、功能實現(xiàn)與使用技巧,需要的朋友可以參考下
    2017-06-06
  • Android仿淘寶商品瀏覽界面圖片滾動效果

    Android仿淘寶商品瀏覽界面圖片滾動效果

    這篇文章主要為大家詳細介紹了Android仿淘寶商品瀏覽界面圖片滾動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-03-03
  • Android定時開機的流程詳解

    Android定時開機的流程詳解

    這篇文章給大家分享了Android定時開機及其實現(xiàn)流程,對此知識點有興趣的朋友,可以學習參考下。
    2018-07-07
  • CDC與BG-CDC的含義電容觸控學習整理

    CDC與BG-CDC的含義電容觸控學習整理

    今天小編就為大家分享一篇關(guān)于CDC與BG-CDC的含義電容觸控學習整理,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Android大作業(yè)功能設(shè)計之自動登錄和記住密碼

    Android大作業(yè)功能設(shè)計之自動登錄和記住密碼

    SharedPreferences是Android平臺上一個輕量級的存儲類,主要是保存一些常用的配置參數(shù),它是采用xml文件存放數(shù)據(jù)的,文件存放在"/data/data<package?name>/shared_prefs"目錄下,由于SharedPreferences是一個接口,而且在這個接口里沒有提供寫入數(shù)據(jù)和讀取數(shù)據(jù)的能力
    2023-01-01
  • Android仿京東首頁畫軸效果

    Android仿京東首頁畫軸效果

    這篇文章主要為大家詳細介紹了Android仿京東首頁畫軸效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android淺析viewBinding和DataBinding

    Android淺析viewBinding和DataBinding

    這篇文章主要介紹了Android淺析viewBinding和DataBinding,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09

最新評論

特克斯县| 平遥县| 阿克陶县| 齐河县| 中江县| 福安市| 两当县| 磐安县| 那坡县| 驻马店市| 色达县| 晋城| 泾阳县| 屯留县| 兴城市| 苏尼特右旗| 永善县| 雷波县| 闸北区| 托里县| 武宣县| 咸丰县| 玉门市| 射洪县| 桑植县| 临清市| 民丰县| 革吉县| 虞城县| 林甸县| 嘉义市| 天峻县| 香格里拉县| 礼泉县| 永和县| 南投县| 屏南县| 榆林市| 石嘴山市| 云林县| 永定县|