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

Android協(xié)程作用域與序列發(fā)生器限制介紹梳理

 更新時(shí)間:2022年08月25日 17:07:22   作者:LeeDuo.  
協(xié)程的作用是什么?協(xié)程是一種輕量級(jí)的線(xiàn)程,解決異步編程的復(fù)雜性,異步的代碼使用協(xié)程可以用順序進(jìn)行表達(dá),文中通過(guò)示例代碼介紹詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧

一.受限協(xié)程作用域

協(xié)程的基礎(chǔ)與使用中提到,可以通過(guò)sequence方法構(gòu)建一個(gè)序列發(fā)生器。但當(dāng)在sequence方法中調(diào)用除了yield方法與yieldAll方法以外的其他掛起方法時(shí),就會(huì)報(bào)錯(cuò)。比如在sequence方法中調(diào)用delay方法,就會(huì)產(chǎn)生下面的報(bào)錯(cuò)提示:

翻譯過(guò)來(lái)大致是“受限的掛起方法只能調(diào)用自身受限的協(xié)程作用域內(nèi)的成員變量或掛起方法。這是什么意思呢?

1.sequence方法

sequence方法就是構(gòu)建序列發(fā)生器用到的方法,內(nèi)部通過(guò)Sequence方法實(shí)現(xiàn),代碼如下:

@SinceKotlin("1.3")
public fun <T> sequence(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Sequence<T> = Sequence { iterator(block) }

其中參數(shù)block是一個(gè)在SequenceScope環(huán)境下的lambda表達(dá)式。

2.SequenceScope類(lèi)

// 注意
@RestrictsSuspension
@SinceKotlin("1.3")
public abstract class SequenceScope<in T> internal constructor() {
    // 向迭代器中提供一個(gè)數(shù)值
    public abstract suspend fun yield(value: T)
    // 向迭代器中提供一組數(shù)值
    public abstract suspend fun yieldAll(iterator: Iterator<T>)
    // 向迭代器中提供Collection類(lèi)型的一組數(shù)值
    public suspend fun yieldAll(elements: Iterable<T>) {
        if (elements is Collection && elements.isEmpty()) return
        return yieldAll(elements.iterator())
    }
    // 向迭代器中提供Sequence類(lèi)型的一組數(shù)值
    public suspend fun yieldAll(sequence: Sequence<T>) = yieldAll(sequence.iterator())
}

SequenceScope類(lèi)是一個(gè)獨(dú)立的抽象類(lèi),沒(méi)有繼承任何的類(lèi)。它提供了四個(gè)方法,只要都是用來(lái)向外提供數(shù)值或?qū)ο?。而該?lèi)成為受限協(xié)程作用域的關(guān)鍵在于該類(lèi)被RestrictsSuspension注解修飾,代碼如下:

@SinceKotlin("1.3")
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
public annotation class RestrictsSuspension

RestrictsSuspension注解用于修飾一個(gè)類(lèi)或接口,表示該類(lèi)是受限的。在被該注解修飾的類(lèi)的擴(kuò)展掛起方法中,只能調(diào)用該注解修飾的類(lèi)中定義的掛起方法,不能調(diào)用其他類(lèi)的掛起方法。

具體的,在sequence方法中,block就是SequenceScope類(lèi)的擴(kuò)展方法,因此在block中,只能使用SequenceScope類(lèi)中提供的掛起方法——yield方法和yieldAll方法。同時(shí),SequenceScope類(lèi)的構(gòu)造器被internal修飾,無(wú)法在外部被繼承,因此也就無(wú)法定義其他的掛起方法。

為什么受限協(xié)程作用域不允許調(diào)用其他的掛起方法呢?

因?yàn)楫?dāng)一個(gè)方法掛起協(xié)程時(shí),會(huì)獲取協(xié)程的續(xù)體,同時(shí)協(xié)程需要等待方法執(zhí)行完畢后的回調(diào),這意味著會(huì)暴露協(xié)程的續(xù)體??赡軙?huì)造成掛起協(xié)程執(zhí)行的不確定性。

二.序列發(fā)生器

1.Sequence接口

首先來(lái)分析一下Sequence接口,代碼如下:

public interface Sequence<out T> {
    public operator fun iterator(): Iterator<T>
}

2.Sequence方法

在協(xié)程中,有一個(gè)與Sequence接口同名的方法,該方法用于返回一個(gè)實(shí)現(xiàn)了Sequence接口的對(duì)象,代碼如下:

@kotlin.internal.InlineOnly
public inline fun <T> Sequence(crossinline iterator: () -> Iterator<T>): Sequence<T> = object : Sequence<T> {
    override fun iterator(): Iterator<T> = iterator()
}

Sequence方法返回了一個(gè)匿名對(duì)象,并通過(guò)參數(shù)中的lambda表達(dá)式iterator實(shí)現(xiàn)了接口中的iterator方法。

從sequence方法的代碼可以知道,用于構(gòu)建序列發(fā)生器的sequence方法內(nèi)部調(diào)用了Sequence方法,同時(shí)還調(diào)用了iterator方法,將返回的Iterator對(duì)象,作為Sequence方法的參數(shù)。

3.iterator方法

@SinceKotlin("1.3")
public fun <T> iterator(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Iterator<T> {
    val iterator = SequenceBuilderIterator<T>()
    iterator.nextStep = block.createCoroutineUnintercepted(receiver = iterator, completion = iterator)
    return iterator
}

iterator方法內(nèi)部創(chuàng)建了一個(gè)SequenceBuilderIterator對(duì)象,并且通過(guò)createCoroutineUnintercepted方法創(chuàng)建了一個(gè)協(xié)程,保存到了SequenceBuilderIterator對(duì)象的nextStep變量中??梢园l(fā)現(xiàn),序列發(fā)生器的核心實(shí)現(xiàn)都在SequenceBuilderIterator類(lèi)中。

4.SequenceBuilderIterator類(lèi)

SequenceBuilderIterator類(lèi)是用于對(duì)序列發(fā)生器進(jìn)行迭代,在該類(lèi)的內(nèi)部對(duì)狀態(tài)進(jìn)行了劃分,代碼如下:

private typealias State = Int
// 沒(méi)有要發(fā)射的數(shù)據(jù)
private const val State_NotReady: State = 0
private const val State_ManyNotReady: State = 1
// 有要發(fā)射的數(shù)據(jù)
private const val State_ManyReady: State = 2
private const val State_Ready: State = 3
// 數(shù)據(jù)全部發(fā)射完畢
private const val State_Done: State = 4
// 發(fā)射過(guò)程中出錯(cuò)
private const val State_Failed: State = 5

狀態(tài)轉(zhuǎn)移圖如下:

迭代器的初始狀態(tài)為State_NotReady,由于首次發(fā)射沒(méi)有數(shù)據(jù),因此會(huì)進(jìn)入State_Failed狀態(tài)。

State_Failed狀態(tài)會(huì)從序列發(fā)生器中獲取數(shù)據(jù),如果是通過(guò)yield方法獲取的數(shù)據(jù),則會(huì)進(jìn)入State_Ready狀態(tài),如果是通過(guò)yieldAll方法獲取的數(shù)據(jù),則會(huì)進(jìn)入State_ManyReady狀態(tài)。

當(dāng)從序列發(fā)生器中獲取數(shù)據(jù)時(shí),如果是在State_ManyReady和State_Ready狀態(tài),則直接發(fā)射一個(gè)數(shù)據(jù),對(duì)應(yīng)的進(jìn)入到State_ManyNotReady和State_NotReady狀態(tài)。如果是在State_ManyNotReady和State_NotReady狀態(tài),則會(huì)判斷是否有數(shù)據(jù),如果有數(shù)據(jù)則對(duì)應(yīng)進(jìn)入到State_ManyReady和State_Ready狀態(tài)。如果沒(méi)有則進(jìn)入到State_Failed狀態(tài),獲取數(shù)據(jù)。

當(dāng)序列發(fā)生器發(fā)射完畢時(shí),會(huì)進(jìn)入State_Done狀態(tài)。

接下來(lái)對(duì)SequenceBuilderIterator類(lèi)進(jìn)行分析。

1.SequenceBuilderIterator類(lèi)的全局變量

SequenceBuilderIterator類(lèi)繼承自SequenceScope類(lèi),實(shí)現(xiàn)了Iterator接口和Continuation接口。代碼如下:

private class SequenceBuilderIterator<T> : SequenceScope<T>(), Iterator<T>, Continuation<Unit> {
    // 迭代器的狀態(tài)
    private var state = State_NotReady
    // 迭代器下一個(gè)要發(fā)送的值
    private var nextValue: T? = null
    // 用于保存yieldAll方法傳入的迭代器
    private var nextIterator: Iterator<T>? = null
    // 用于獲取下一個(gè)數(shù)據(jù)的續(xù)體
    var nextStep: Continuation<Unit>? = null
    ...
    // 空的上下文
    override val context: CoroutineContext
        get() = EmptyCoroutineContext
}

為什么SequenceBuilderIterator類(lèi)的上下文是空的呢?

因?yàn)镾equenceBuilderIterator類(lèi)繼承了SequenceScope類(lèi),因此該類(lèi)也是受限的,因此不允許在類(lèi)的擴(kuò)展方法中調(diào)用類(lèi)內(nèi)以外的掛起方法。自然也就不能進(jìn)行調(diào)度、攔截等操作,所以上下文為空。在協(xié)程中,受限協(xié)程的上下文一般都是空上下文。

2.yield方法與yieldAll方法

yield方法與yieldAll方法是SequenceScope類(lèi)中定義的兩個(gè)方法,在SequenceBuilderIterator類(lèi)中的實(shí)現(xiàn)如下:

// 發(fā)射一個(gè)數(shù)據(jù)
override suspend fun yield(value: T) {
    // 保存數(shù)據(jù)到全局變量中
    nextValue = value
    // 修改狀態(tài)
    state = State_Ready
    // 掛起協(xié)程,獲取續(xù)體
    return suspendCoroutineUninterceptedOrReturn { c ->
        // 保存續(xù)體到全局變量中
        nextStep = c
        // 掛起
        COROUTINE_SUSPENDED
    }
}
// 發(fā)射多個(gè)數(shù)據(jù)
override suspend fun yieldAll(iterator: Iterator<T>) {
    // 如果迭代器沒(méi)有數(shù)據(jù),則直接返回
    if (!iterator.hasNext()) return
    // 如果有數(shù)據(jù),則保存到全局變量
    nextIterator = iterator
    // 修改狀態(tài)
    state = State_ManyReady
    // 掛起協(xié)程,獲取續(xù)體
    return suspendCoroutineUninterceptedOrReturn { c ->
        // 保存續(xù)體到全局變量中
        nextStep = c
        // 掛起
        COROUTINE_SUSPENDED
    }
}

通過(guò)上面的代碼可以知道,yield方法和yieldAll方法主要做了三件事情,掛起協(xié)程、修改狀態(tài)、保存要發(fā)送的數(shù)據(jù)和續(xù)體。而yieldAll發(fā)射多個(gè)數(shù)據(jù)原理在于保存了參數(shù)中Iterator接口指向的對(duì)象,通過(guò)迭代器獲取數(shù)據(jù)。

3.hasNext方法

hasNext方法是Iterator接口中定義的方法,用于迭代時(shí)判斷是否還有數(shù)據(jù),代碼如下:

override fun hasNext(): Boolean {
    // 循環(huán)
    while (true) {
        // 判斷狀態(tài)
        when (state) {
            // 剛通過(guò)yield方法發(fā)射數(shù)據(jù)
            State_NotReady -> {}
            // 剛通過(guò)yieldAll方法發(fā)射數(shù)據(jù)
            State_ManyNotReady ->
                // 如果迭代器中還有數(shù)據(jù)
                if (nextIterator!!.hasNext()) {
                    // 修改狀態(tài),返回true
                    state = State_ManyReady
                    return true
                } else {
                    // 沒(méi)有數(shù)據(jù),則置空,丟棄迭代器
                    nextIterator = null
                }
            // 如果序列發(fā)生器已經(jīng)發(fā)射完數(shù)據(jù),返回false
            State_Done -> return false
            // 如果有數(shù)據(jù),則直接返回true
            State_Ready, State_ManyReady -> return true
            // 其他狀態(tài),則拋出異常
            else -> throw exceptionalState()
        }
        // 走到這里,說(shuō)明需要去獲取下一個(gè)數(shù)據(jù)
        // 修改狀態(tài)
        state = State_Failed
        // 獲取全局保存的續(xù)體
        val step = nextStep!!
        // 置空
        nextStep = null
        // 恢復(fù)序列發(fā)生器的執(zhí)行,直到遇到y(tǒng)ield方法或yieldAll方法掛起
        step.resume(Unit)
    }
}
// 異常狀態(tài)的處理
private fun exceptionalState(): Throwable = when (state) {
    State_Done -> NoSuchElementException()
    State_Failed -> IllegalStateException("Iterator has failed.")
    else -> IllegalStateException("Unexpected state of the iterator: $state")
}

4.next方法

next方法也是Iterator接口中定義的方法,用于在迭代器中存在數(shù)據(jù)時(shí)獲取數(shù)據(jù),代碼如下:

override fun next(): T {
    // 判斷狀態(tài)
    when (state) {
        // 如果當(dāng)前處于已經(jīng)發(fā)射完數(shù)據(jù)的狀態(tài),則判斷是否有數(shù)據(jù)
        State_NotReady, State_ManyNotReady -> return nextNotReady()
        // 如果通過(guò)yieldAll方法獲取到了數(shù)據(jù)
        State_ManyReady -> {
            // 修改狀態(tài)
            state = State_ManyNotReady
            // 通過(guò)迭代器獲取數(shù)據(jù)
            return nextIterator!!.next()
        }
        // 如果通過(guò)yield方法獲取到了數(shù)據(jù)
        State_Ready -> {
            // 修改狀態(tài)
            state = State_NotReady
            // 獲取保存的數(shù)據(jù)并進(jìn)行類(lèi)型轉(zhuǎn)換
            @Suppress("UNCHECKED_CAST")
            val result = nextValue as T
            // 全局變量置空
            nextValue = null
            // 返回?cái)?shù)據(jù)
            return result
        }
        // 其他情況,則拋出異常
        else -> throw exceptionalState()
    }
}
// 如果沒(méi)有數(shù)據(jù),則拋出異常,有數(shù)據(jù),則返回?cái)?shù)據(jù)
private fun nextNotReady(): T {
    if (!hasNext()) throw NoSuchElementException() else return next()
}

5.總結(jié)

當(dāng)使用序列發(fā)生器進(jìn)行迭代時(shí),首先會(huì)調(diào)用hasNext方法,hasNext方法會(huì)通過(guò)保存的續(xù)體,恢復(fù)序列發(fā)生器所在的協(xié)程繼續(xù)執(zhí)行,獲取下一次待發(fā)射的數(shù)據(jù)。如果獲取了到數(shù)據(jù),則會(huì)返回true,這樣之后通過(guò)next方法就可以獲取到對(duì)應(yīng)的數(shù)據(jù)。

當(dāng)序列發(fā)生器所在的協(xié)程在執(zhí)行中遇到y(tǒng)ield方法時(shí),會(huì)發(fā)生掛起,同時(shí)將下一次待發(fā)射的數(shù)據(jù)保存起來(lái)。如果遇到的是yieldAll方法,則保存的是迭代器,下一次發(fā)射數(shù)據(jù)時(shí)會(huì)從迭代器中獲取。

到此這篇關(guān)于A(yíng)ndroid協(xié)程作用域與序列發(fā)生器限制介紹梳理的文章就介紹到這了,更多相關(guān)Android協(xié)程作用域內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Flutter實(shí)現(xiàn)底部導(dǎo)航欄效果

    Flutter實(shí)現(xiàn)底部導(dǎo)航欄效果

    這篇文章主要為大家詳細(xì)介紹了Flutter實(shí)現(xiàn)底部導(dǎo)航欄效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Android自定義View簡(jiǎn)易折線(xiàn)圖控件(二)

    Android自定義View簡(jiǎn)易折線(xiàn)圖控件(二)

    這篇文章主要為大家詳細(xì)介紹了Android自定義View簡(jiǎn)易折線(xiàn)圖控件的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • Android實(shí)現(xiàn)網(wǎng)絡(luò)圖片瀏覽器

    Android實(shí)現(xiàn)網(wǎng)絡(luò)圖片瀏覽器

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)網(wǎng)絡(luò)圖片瀏覽器的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 很棒的Android彈幕效果實(shí)例

    很棒的Android彈幕效果實(shí)例

    這篇文章主要為大家詳細(xì)介紹了很棒的Android彈幕效果實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android 自定義View的使用介紹

    Android 自定義View的使用介紹

    本篇文章小編為大家介紹,Android 自定義View的使用。需要的朋友參考下
    2013-04-04
  • Android Kotlin的使用及簡(jiǎn)單實(shí)例

    Android Kotlin的使用及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了Android Kotlin的使用及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • RxJava2 線(xiàn)程調(diào)度的方法

    RxJava2 線(xiàn)程調(diào)度的方法

    這篇文章主要介紹了RxJava2 線(xiàn)程調(diào)度的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-03-03
  • Android組件化原理詳細(xì)介紹

    Android組件化原理詳細(xì)介紹

    這篇文章主要介紹了Android組件化原理詳細(xì)介紹,組件化架構(gòu)的目的是讓各個(gè)業(yè)務(wù)變得相對(duì)獨(dú)立,各個(gè)組件在組件模式下可以獨(dú)立開(kāi)發(fā)調(diào)試
    2022-07-07
  • Android簡(jiǎn)單實(shí)現(xiàn)文件下載

    Android簡(jiǎn)單實(shí)現(xiàn)文件下載

    這篇文章主要為大家詳細(xì)介紹了Android簡(jiǎn)單實(shí)現(xiàn)文件下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • android實(shí)現(xiàn)滑動(dòng)標(biāo)簽頁(yè)效果的代碼解析

    android實(shí)現(xiàn)滑動(dòng)標(biāo)簽頁(yè)效果的代碼解析

    這篇文章主要介紹了android實(shí)現(xiàn)滑動(dòng)標(biāo)簽頁(yè)效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04

最新評(píng)論