将两个状态流合并成新的状态流

问题描述

我有两个状态流。是否有可能将它们结合起来并获得新的状态流?从逻辑上讲,这应该是可能的,因为两个状态流都有初始值,但正如我所见,组合函数只返回 Flow 而不是 StateFlow。

解决方法

到目前为止我创建了函数:

fun <T1,T2,R> combineState(
        flow1: StateFlow<T1>,flow2: StateFlow<T2>,scope: CoroutineScope = GlobalScope,sharingStarted: SharingStarted = SharingStarted.Eagerly,transform: (T1,T2) -> R
): StateFlow<R> = combine(flow1,flow2) {
    o1,o2 -> transform.invoke(o1,o2)
}.stateIn(scope,sharingStarted,transform.invoke(flow1.value,flow2.value))
,

您可以使用 combine 运算符,然后对由此产生的 stateIn 使用 Flow 函数。

来自 kotlinx 协程存储库中的 stateIn documentation

stateIn 函数“将 cold Flow 转换为在给定协程范围内启动的 hot StateFlow,与多个下游订阅者共享来自上游流的单个运行实例的最近发出的值。”

截至撰写本文时,其签名是:

fun <T> Flow<T>.stateIn(
  scope: CoroutineScope,started: SharingStarted,initialValue: T
): StateFlow<T> (source)

因此,您应该能够对 Flow 进行任何需要的转换,包括组合它们,然后最终使用 stateIn 将它们转换回 StateFlow。>

它可能看起来像这样(也许是创建一个拼字游戏点数计算器):

val wordFlow = MutableStateFlow("Hi")
val pointFlow = MutableStateFlow(5)

val stateString = wordFlow.combine(pointFlow) { word,points ->
    "$word is worth $points points"
}.stateIn(viewModelScope,SharingStarted.Eagerly,"Default is worth 0 points")

stateString 的类型为 StateFlow<String>,并且您已成功将另外两个 StateFlows 合并为一个 StateFlow

,

合并 n 个状态流

@Suppress("CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS")
inline fun <reified T,R> combineStateFlow(
    vararg flows: StateFlow<T>,crossinline transform: (Array<T>) -> R
): StateFlow<R> = combine(flows = flows) {
    transform.invoke(it)
}.stateIn(
    scope = scope,started = sharingStarted,initialValue = transform.invoke(flows.map {
        it.value
    }.toTypedArray())
)

使用:

data class A(val a: String)
data class B(val b: Int)

private val test1 = MutableStateFlow(A("a"))
private val test2 = MutableStateFlow(B(2))
@Suppress("CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS")
private val _isValidForm = combineStateFlow(
    flows = arrayOf(test1,test2),scope = viewModelScope
) { combinedFlows: Array<Any> ->
    combinedFlows.map {
        val doSomething = when (it) {
            is A -> true
            is B -> false
            else -> false
        }
    }
}

Gist

,

使用 combine 运算符,需要两个流和一个转换函数来组合两个流的结果。

 val int = MutableStateFlow(2)
 val double = MutableStateFlow(1.8)
 int.combine(double){ i,d ->
            i + d             
 }.collect(::println)