Android-Flow的構(gòu)造簡(jiǎn)易拆解和一點(diǎn)思考

自上而下,關(guān)注整體思路,文章不考慮更多細(xì)節(jié)

//flow示例
        CoroutineScope(Dispatchers.Default).launch {
            flow {
             //這部分就是collector
                (1..a).forEach{
                    delay(1000)
                    emit(it + 1)
                }
            }.collect {
                Log.e("flow collect"," $it")
            }
        }

拆解

class FlowCollectorImpl<Int>: FlowCollector<Int> {
    suspend fun block(){
        (1..a).forEach {
            // 每隔 1 秒發(fā)射 1 個(gè)數(shù)字
            delay(1000)
            emit(it + 1)
        }
    }

    override suspend fun emit(value: Int) {
        Log.e("flow collect"," $it")// 打印數(shù)字
    }
}
//源碼中的內(nèi)容示意
private class Flow<T>(private val block: suspend FlowCollector<T>.() -> Unit) : AbstractFlow<T>() {
    override suspend fun collect(collector: FlowCollector<T>) {
        collector.block() //引擎點(diǎn)火!
    }
}

如果之前不太明白這點(diǎn)的通過(guò)上面拆解代碼應(yīng)該可以有所得

部分源碼

public fun interface FlowCollector<in T> {
    public suspend fun emit(value: T)
}
public fun <T> flow(
   @BuilderInference block: suspend FlowCollector<T>.() -> Unit
): Flow<T> = SafeFlow(block)


    private class SafeFlow<T>(private val block: suspend FlowCollector<T>.() -> Unit) : kotlinx.coroutines.flow.Flow<T>,
        CancellableFlow<T> {




        public final override suspend fun collect(collector: FlowCollector<T>) {
            val safeCollector = SafeCollector(collector, coroutineContext)
            try {
                collectSafely(safeCollector)
            } finally {
                safeCollector.releaseIntercepted()
            }
        }

        override suspend fun collectSafely(collector: FlowCollector<T>) {
            collector.block()
            //相當(dāng)于調(diào)用上面拆解的block(),block()中調(diào)用了emit(),開始發(fā)射并收集數(shù)據(jù)
        }
    }

flow{}后面的lambda其實(shí)相當(dāng)于就是FlowCollector的一個(gè)擴(kuò)展函數(shù),
collect{ }后面的lambda就是emit方法的實(shí)現(xiàn)。

調(diào)用collect之后,會(huì)調(diào)用collector.block(),而block()調(diào)用了emit(),從而開始打印數(shù)據(jù)。


Flow的filter、map等方法原理和關(guān)鍵源碼:

核心原理:過(guò)濾本質(zhì)是依次收集原flow數(shù)據(jù)后按設(shè)定條件過(guò)濾或轉(zhuǎn)換后生成新的flow對(duì)象,發(fā)射新的轉(zhuǎn)換后的數(shù)據(jù)!

filter和map方法都是使用transform()實(shí)現(xiàn),而transform()其實(shí)就是接收了上游數(shù)據(jù)后,再生成新的flow發(fā)給下游。

public inline fun <T> Flow<T>.filter(crossinline predicate: suspend (T) -> Boolean): Flow<T> = transform { value ->
    if (predicate(value)) return@transform emit(value)
}
public inline fun <T, R> Flow<T>.transform(
    @BuilderInference crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit
): Flow<R> = flow { // Note: safe flow is used here, because collector is exposed to transform on each operation
    collect { value ->
        // kludge, without it Unit will be returned and TCE won't kick in, KT-28938
        return@collect transform(value)
    }
}

上面的源碼中,會(huì)生成一個(gè)新的Flow對(duì)象,而該Flow對(duì)象的數(shù)據(jù)源(收集者)就是從原Flow數(shù)據(jù)中collect的數(shù)據(jù)。然后經(jīng)過(guò)轉(zhuǎn)換,再次發(fā)射出去,而這個(gè)新Flow就是下游即將接收的經(jīng)過(guò)篩選或轉(zhuǎn)換后的新數(shù)據(jù)流。

看上面源碼中的其中部分

collect { value ->
        // kludge, without it Unit will be returned and TCE won't kick in, KT-28938
        return@collect transform(value)
    }

這部分就是收集原flow中的數(shù)據(jù),然后按轉(zhuǎn)換條件去發(fā)射新的數(shù)據(jù)。(transform方法中會(huì)執(zhí)行emit(value) )。


冷流的設(shè)計(jì)核心部分就是依靠函數(shù)參數(shù)這一特性來(lái)實(shí)現(xiàn)的(函數(shù)參數(shù)大多數(shù)情況為lambda表達(dá)式),函數(shù)參數(shù)是kotlin最具創(chuàng)造性和顛覆性的特性之一,也是源碼中很多復(fù)雜方法看起來(lái)難以理解的原因之一。函數(shù)參數(shù)就是一個(gè)死參數(shù),開發(fā)者可以直接執(zhí)行它(),或者不去執(zhí)行而是繼續(xù)向下傳遞該函數(shù)參數(shù),如果你不主動(dòng)去調(diào)用它(),它是不會(huì)執(zhí)行它方法體內(nèi)的代碼的。比如上面案例源碼:

flow { // Note: safe flow is used here, because collector is exposed to transform on each operation
    collect { value ->
        // kludge, without it Unit will be returned and TCE won't kick in, KT-28938
        return@collect transform(value)
    }
}

生成新的flow時(shí),雖然其內(nèi)部調(diào)用了collect{},但是其并沒(méi)有真正執(zhí)行(它重寫了emit()),只是作為一個(gè)參數(shù)繼續(xù)在flow構(gòu)造內(nèi)部向下傳遞該參數(shù),最后在

private class SafeFlow<T>(private val block: suspend FlowCollector<T>.() -> Unit) : AbstractFlow<T>() {
    override suspend fun collectSafely(collector: FlowCollector<T>) {
        collector.block()
    }
}
    public final override suspend fun collect(collector: FlowCollector<T>) {
        val safeCollector = SafeCollector(collector, coroutineContext)
        try {
            collectSafely(safeCollector)
        } finally {
            safeCollector.releaseIntercepted()
        }
    }

上面中的collectSafely()中才真正被執(zhí)行,上面是使用函數(shù)參數(shù)(FlowCollector的擴(kuò)展函數(shù),這個(gè)擴(kuò)展函數(shù)就是生成flow{}時(shí)其內(nèi)的lambda表達(dá)式)重寫了collectSafely()!而collectSafely()是在collect()中執(zhí)行的,也就是開始收集時(shí)才執(zhí)行的,這就形成了閉環(huán)。這也是冷流的‘冷’原因所在,前期的工作是在“造車”,最后的執(zhí)行才“點(diǎn)火啟動(dòng)”。

這一特性,使得kotlin擁有了無(wú)與倫比的功能構(gòu)造能力。方法可以先通過(guò)傳遞函數(shù)參數(shù)來(lái)構(gòu)造功能的整體架構(gòu),構(gòu)造完成之后最后去執(zhí)行來(lái)實(shí)現(xiàn)整個(gè)功能的運(yùn)轉(zhuǎn)。


如有問(wèn)題,歡迎各位指正,感謝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容