从零自制一个Flow

383 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

前言

随着官方的例子也在Activity里使用Flow(配上repeatOnLifecycle),LiveData也许会被StateFlowSharedFlow替代了。那么到底Flow是怎样实现的呢?

扒一扒源代码,原来没有特别复杂。现在让我们从零开始自己写一个看看,顺便加深一下理解。

基本型

先设想一个简单的场景:定义一个函数(之后可以在别处调用)

fun main() {
    val live: () -> Unit = {
        print("吃")
        print("睡")
    }
    live()
    live()
}

将会输出:

吃
睡

加强版1

加一个(String) -> Unit类型的函数作为参数。我们可以在live内部调用这个函数,并给它定义一个名字emit。

fun main() {
    val live: ((String) -> Unit) -> Unit = { emit ->
        emit("吃")
        emit("睡")
    }
    live { print(it) }
    live { print(it) }
}

输出:

吃
睡

加强版2

下面定义一个接口FlowCollector

fun interface FlowController {
    fun emit(value: String)
}

// 更新如下
fun main() {
    val live: (FlowCollector) -> Unit = {
        it.emit("吃")
        it.emit("睡")
    }
    live { print(it) }
    live { print(it) }
}

输出同上。

it.emit(...) 看起来有点麻烦,能不能简化一下呢?

加强版3

fun interface FlowController {
    fun emit(value: String)
}

// 把FlowCollector设为Receiver
fun main() {
    val live: FlowCollector.() -> Unit = {
        emit("吃")
        emit("睡")
    }
    live { print(it) } // 吃
    live { print(it) } // 睡
}

官方文档没有详细介绍Receiver的概念,感兴趣的同学可以自行搜索。。

再尝试把live的调用交给一个实例:

加强版4


interface Flow {
    fun collect(collector: FlowCollector)
}

fun interface FlowController {
    fun emit(value: String)
}

fun main() {
    val live: FlowCollector.() -> Unit = {
        emit("吃")
        emit("睡")
    }
    val flow: Flow = object : Flow {
        override fun collect(collector: FlowCollector) {
            collector.live()
        }
    }
    flow.collect { print(it) } // 吃
    flow.collect { print(it) } // 睡
}

把生成实例的代码抽象出来:

加强版5

interface Flow {
    fun collect(collector: FlowCollector)
}

fun interface FlowController {
    fun emit(value: String)
}

fun flow(builder: FlowCollector.() -> Unit) = object : Flow {
    override fun collect(collector: FlowCollector) {
        collector.builder()
    }
}

fun main() {
    val live: Flow = flow {
        emit("吃")
        emit("睡")
    }
    live.collect { print(it) } // 吃
    live.collect { print(it) } // 睡
}

注意到上面的FlowController接收的是String类型,可以继续抽象化:

interface Flow<T> {
    fun collect(collector: FlowCollector<T>)
}

fun interface FlowController<T> {
    fun emit(value: T)
}

fun <T> flow(builder: FlowCollector<T>.() -> Unit) = object : Flow<T> {
    override fun collect(collector: FlowCollector<T>) {
        collector.builder()
    }
}

fun main() {
    val live: Flow<String> = flow {
        emit("吃")
        emit("睡")
    }
    live.collect { print(it) } // 吃
    live.collect { print(it) } // 睡
}

是不是已经和平时看到的Flow差不多了?再加把力,把异步支持也添上:

完整版

interface Flow<T> {
    suspend fun collect(collector: FlowCollector<T>)
}

fun interface FlowController<T> {
    suspend fun emit(value: T)
}

fun <T> flow(builder: FlowCollector<T>.() -> Unit) = object : Flow<T> {
    override suspend fun collect(collector: FlowCollector<T>) {
        collector.builder()
    }
}

suspend fun main() {
    val live: Flow<String> = flow {
        emit("吃")
        emit("睡")
    }
    live.collect { print(it) } // 吃
    live.collect { print(it) } // 睡
}

回头翻翻源代码,几乎一致。其实知道思路之后实现也并不复杂,不过难就难在想到这种做法。