欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Kotlin協(xié)程上下文與上下文元素深入理解

 更新時間:2022年08月01日 11:29:48   作者:LeeDuo.  
協(xié)程上下文是一個有索引的Element實例集合,每個element在這個集合里有一個唯一的key;協(xié)程上下文包含用戶定義的一些數(shù)據(jù)集合,這些數(shù)據(jù)與協(xié)程密切相關(guān);協(xié)程上下文用于控制線程行為、協(xié)程的生命周期、異常以及調(diào)試

一.EmptyCoroutineContext

EmptyCoroutineContext代表空上下文,由于自身為空,因此get方法的返回值是空的,fold方法直接返回傳入的初始值,plus方法也是直接返回傳入的context,minusKey方法返回自身,代碼如下:

public object EmptyCoroutineContext : CoroutineContext, Serializable {
    private const val serialVersionUID: Long = 0
    private fun readResolve(): Any = EmptyCoroutineContext
    public override fun <E : Element> get(key: Key<E>): E? = null
    public override fun <R> fold(initial: R, operation: (R, Element) -> R): R = initial
    public override fun plus(context: CoroutineContext): CoroutineContext = context
    public override fun minusKey(key: Key<*>): CoroutineContext = this
    public override fun hashCode(): Int = 0
    public override fun toString(): String = "EmptyCoroutineContext"
}

二.CombinedContext

CombinedContext是組合上下文,是存儲Element的重要的數(shù)據(jù)結(jié)構(gòu)。內(nèi)部存儲的組織結(jié)構(gòu)如下圖所示:

可以看出CombinedContext是一種左偏(從左向右計算)的列表,這么設(shè)計的目的是為了讓CoroutineContext中的plus方法工作起來更加自然。

由于采用這種數(shù)據(jù)結(jié)構(gòu),CombinedContext類中的很多方法都是通過循環(huán)實現(xiàn)的,代碼如下:

internal class CombinedContext(
    // 數(shù)據(jù)結(jié)構(gòu)左邊可能為一個Element對象或者還是一個CombinedContext對象
    private val left: CoroutineContext,
    // 數(shù)據(jù)結(jié)構(gòu)右邊只能為一個Element對象
    private val element: Element
) : CoroutineContext, Serializable {
    override fun <E : Element> get(key: Key<E>): E? {
        var cur = this
        while (true) {
            // 進(jìn)行g(shù)et操作,如果當(dāng)前CombinedContext對象中存在,則返回
            cur.element[key]?.let { return it }
            // 獲取左邊的上下文對象
            val next = cur.left
            // 如果是CombinedContext對象
            if (next is CombinedContext) {
                // 賦值,繼續(xù)循環(huán)
                cur = next
            } else { // 如果不是CombinedContext對象
                // 進(jìn)行g(shù)et操作,返回
                return next[key]
            }
        }
    }
    // 數(shù)據(jù)結(jié)構(gòu)左右分開操作,從左到右進(jìn)行fold運算
    public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =
        operation(left.fold(initial, operation), element)
    public override fun minusKey(key: Key<*>): CoroutineContext {
        // 如果右邊是指定的Element對象,則返回左邊
        element[key]?.let { return left }
        // 調(diào)用左邊的minusKey方法
        val newLeft = left.minusKey(key)
        return when {
            // 這種情況,說明左邊部分已經(jīng)是去掉指定的Element對象的,右邊也是如此,因此返回當(dāng)前對象,不需要在進(jìn)行包裹
            newLeft === left -> this
            // 這種情況,說明左邊部分包含指定的Element對象,因此返回只右邊
            newLeft === EmptyCoroutineContext -> element
            // 這種情況,返回的左邊部分是新的,因此需要和右邊部分一起包裹后,再返回
            else -> CombinedContext(newLeft, element)
        }
    }
    private fun size(): Int {
        var cur = this
        //左右各一個
        var size = 2
        while (true) {
            cur = cur.left as? CombinedContext ?: return size
            size++
        }
    }
    // 通過get方法實現(xiàn)
    private fun contains(element: Element): Boolean =
        get(element.key) == element
    private fun containsAll(context: CombinedContext): Boolean {
        var cur = context
        // 循環(huán)展開每一個CombinedContext對象,每個CombinedContext對象中的Element對象都要包含
        while (true) {
            if (!contains(cur.element)) return false
            val next = cur.left
            if (next is CombinedContext) {
                cur = next
            } else {
                return contains(next as Element)
            }
        }
    }
    ...
}

三.Key與Element

Key接口與Element接口定義在CoroutineContext接口中,代碼如下:

public interface Key<E : Element>
public interface Element : CoroutineContext {
    // 一個Key對應(yīng)著一個Element對象
    public val key: Key<*>
    // 相等則強制轉(zhuǎn)換并返回,否則則返回空
    public override operator fun <E : Element> get(key: Key<E>): E? =
        @Suppress("UNCHECKED_CAST")
        if (this.key == key) this as E else null
    // 自身與初始值進(jìn)行fold操作
    public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =
        operation(initial, this)
    // 如果要去除的是當(dāng)前的Element對象,則返回空的上下文,否則返回自身
    public override fun minusKey(key: Key<*>): CoroutineContext =
        if (this.key == key) EmptyCoroutineContext else this
}

四.CoroutineContext

CoroutineContext接口定義了協(xié)程上下文的基本行為以及Key和Element接口。同時,重載了"+"操作,相關(guān)代碼如下:

public interface CoroutineContext {
    public operator fun <E : Element> get(key: Key<E>): E?
    public fun <R> fold(initial: R, operation: (R, Element) -> R): R
    public operator fun plus(context: CoroutineContext): CoroutineContext =
        // 如果要與空上下文相加,則直接但會當(dāng)前對象,
        if (context === EmptyCoroutineContext) this else
            // 當(dāng)前Element作為初始值
            context.fold(this) { acc, element ->
                // acc:已經(jīng)加完的CoroutineContext對象
                // element:當(dāng)前要加的CoroutineContext對象
                // 獲取從acc中去掉element后的上下文removed,這步是為了確保添加重復(fù)的Element時,移動到最右側(cè)
                val removed = acc.minusKey(element.key)
                // 去除掉element后為空上下文(說明acc中只有一個Element對象),則返回element
                if (removed === EmptyCoroutineContext) element else {
                    // ContinuationInterceptor代表攔截器,也是一個Element對象
                    // 下面的操作是為了把攔截器移動到上下文的最右端,為了方便快速獲取
                    // 從removed中獲取攔截器
                    val interceptor = removed[ContinuationInterceptor]
                    // 若上下文中沒有攔截器,則進(jìn)行累加(包裹成CombinedContext對象),返回
                    if (interceptor == null) CombinedContext(removed, element) else {
                        // 若上下文中有攔截器
                        // 獲取上下文中移除到掉攔截器后的上下文left
                        val left = removed.minusKey(ContinuationInterceptor)
                        // 若移除到掉攔截器后的上下文為空上下文,說明上下文left中只有一個攔截器,
                        // 則進(jìn)行累加(包裹成CombinedContext對象),返回
                        if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else
                            // 否則,現(xiàn)對當(dāng)前要加的element和left進(jìn)行累加,然后在和攔截器進(jìn)行累加
                            CombinedContext(CombinedContext(left, element), interceptor)
                    }
                }
            }
    public fun minusKey(key: Key<*>): CoroutineContext
    ... // (Key和Element接口)
}
  • 1.plus方法圖解

假設(shè)我們有一個上下文順序為A、B、C,現(xiàn)在要按順序加上D、C、A。

1)初始值A(chǔ)、B、C

2)加上D

3)加上C

4)加上A

  • 2.為什么要將ContinuationInterceptor放到協(xié)程上下文的最右端?

在協(xié)程中有大量的場景需要獲取ContinuationInterceptor。根據(jù)之前分析的CombinedContext的minusKey方法,ContinuationInterceptor放在上下文的最右端,可以直接獲取,不需要經(jīng)過多次的循環(huán)。

五.AbstractCoroutineContextKey與AbstractCoroutineContextElement

AbstractCoroutineContextElement實現(xiàn)了Element接口,將Key對象作為構(gòu)造方法必要的參數(shù)。

public abstract class AbstractCoroutineContextElement(public override val key: Key<*>) : Element

AbstractCoroutineContextKey用于實現(xiàn)Element的多態(tài)。什么是Element的多態(tài)呢?假設(shè)類A實現(xiàn)了Element接口,Key為A。類B繼承自類A,Key為B。這時將類B的對象添加到上下文中,通過指定不同的Key(A或B),可以得到不同類型對象。具體代碼如下:

// baseKey為衍生類的基類的Key
// safeCast用于對基類進(jìn)行轉(zhuǎn)換
// B為基類,E為衍生類
public abstract class AbstractCoroutineContextKey<B : Element, E : B>(
    baseKey: Key<B>,
    private val safeCast: (element: Element) -> E?
) : Key<E> {
    // 頂置Key,如果baseKey是AbstractCoroutineContextKey,則獲取baseKey的頂置Key
    private val topmostKey: Key<*> = if (baseKey is AbstractCoroutineContextKey<*, *>) baseKey.topmostKey else baseKey
    // 用于類型轉(zhuǎn)換
    internal fun tryCast(element: Element): E? = safeCast(element)
    // 用于判斷當(dāng)前key是否是指定key的子key
    // 邏輯為與當(dāng)前key相同,或者與當(dāng)前key的頂置key相同
    internal fun isSubKey(key: Key<*>): Boolean = key === this || topmostKey === key
}

getPolymorphicElement方法與minusPolymorphicKey方法

如果衍生類使用了AbstractCoroutineContextKey,那么基類在實現(xiàn)Element接口中的get方法時,就需要通過getPolymorphicElement方法,實現(xiàn)minusKey方法時,就需要通過minusPolymorphicKey方法,代碼如下:

public fun <E : Element> Element.getPolymorphicElement(key: Key<E>): E? {
    // 如果key是AbstractCoroutineContextKey
    if (key is AbstractCoroutineContextKey<*, *>) {
        // 如果key是當(dāng)前key的子key,則基類強制轉(zhuǎn)換成衍生類,并返回
        @Suppress("UNCHECKED_CAST")
        return if (key.isSubKey(this.key)) key.tryCast(this) as? E else null
    }
    // 如果key不是AbstractCoroutineContextKey
    // 如果key相等,則強制轉(zhuǎn)換,并返回
    @Suppress("UNCHECKED_CAST")
    return if (this.key === key) this as E else null
}
public fun Element.minusPolymorphicKey(key: Key<*>): CoroutineContext {
    // 如果key是AbstractCoroutineContextKey
    if (key is AbstractCoroutineContextKey<*, *>) {
        // 如果key是當(dāng)前key的子key,基類強制轉(zhuǎn)換后不為空,說明當(dāng)前Element需要去掉,因此返回空上下文,否則返回自身
        return if (key.isSubKey(this.key) && key.tryCast(this) != null) EmptyCoroutineContext else this
    }
    // 如果key不是AbstractCoroutineContextKey
    // 如果key相等,說明當(dāng)前Element需要去掉,因此返回空上下文,否則返回自身
    return if (this.key === key) EmptyCoroutineContext else this
}

到此這篇關(guān)于Kotlin協(xié)程上下文與上下文元素深入理解的文章就介紹到這了,更多相關(guān)Kotlin上下文內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android AsyncTask用法巧用實例代碼

    Android AsyncTask用法巧用實例代碼

    這篇文章主要介紹了Android AsyncTask用法巧用實例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • android實現(xiàn)音樂播放器

    android實現(xiàn)音樂播放器

    這篇文章主要為大家詳細(xì)介紹了android實現(xiàn)音樂播放器,擁有播放、暫停、重新播放和停止等功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • Android中實現(xiàn)OkHttp上傳文件到服務(wù)器并帶進(jìn)度

    Android中實現(xiàn)OkHttp上傳文件到服務(wù)器并帶進(jìn)度

    本篇文章主要介紹了Android中實現(xiàn)OkHttp上傳文件到服務(wù)器并帶進(jìn)度,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • flutter局部刷新的實現(xiàn)示例

    flutter局部刷新的實現(xiàn)示例

    這篇文章主要介紹了flutter局部刷新的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Android使用RSA加密實現(xiàn)接口調(diào)用時的校驗功能

    Android使用RSA加密實現(xiàn)接口調(diào)用時的校驗功能

    這篇文章主要介紹了Android+Java使用RSA加密實現(xiàn)接口調(diào)用時的校驗功能,幫助大家更好的利用Android進(jìn)行開發(fā),感興趣的朋友可以了解下
    2020-12-12
  • Android仿新浪微博分頁管理界面(3)

    Android仿新浪微博分頁管理界面(3)

    這篇文章主要為大家詳細(xì)介紹了Android仿新浪微博分頁管理界面,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android Studio 3.1.3升級至3.6.1后舊項目的兼容操作方法

    Android Studio 3.1.3升級至3.6.1后舊項目的兼容操作方法

    這篇文章主要介紹了Android Studio 3.1.3升級至3.6.1后舊項目的兼容操作方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • Android實現(xiàn)控件的縮放移動功能

    Android實現(xiàn)控件的縮放移動功能

    這篇文章主要介紹了android控件的縮放,移動功能,本文圖文并茂給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2018-01-01
  • 淺談Android串口通訊SerialPort原理

    淺談Android串口通訊SerialPort原理

    這篇文章主要介紹了淺談Android串口通訊SerialPort原理,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • Android記事本項目開發(fā)

    Android記事本項目開發(fā)

    這篇文章主要為大家詳細(xì)介紹了Android記事本項目開發(fā)的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12

最新評論