7

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

4

5 回答 5

4

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

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))
于 2020-12-25T01:45:07.933 回答
4

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

从kotlinx 协程存储库中的stateIn 文档:

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

在撰写本文时,它的签名是:

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

所以你应该能够对你Flow的 s 做任何你需要的转换,包括组合它们,然后最终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.

于 2021-04-18T16:51:54.827 回答
1

与@Nikola Despotoski 类似的解决方案,但以扩展函数的形式

/**
 * Combines two [StateFlow]s into a single [StateFlow]
 */
fun <T1, T2, R> StateFlow<T1>.combineState(
  flow2: StateFlow<T2>,
  scope: CoroutineScope = GlobalScope,
  sharingStarted: SharingStarted = SharingStarted.Eagerly,
  transform: (T1, T2) -> R
): StateFlow<R> = combine(this, flow2) { o1, o2 -> transform.invoke(o1, o2) }
  .stateIn(scope, sharingStarted, transform.invoke(this.value, flow2.value))
于 2021-09-01T06:05:55.990 回答
0

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

 val int = MutableStateFlow(2)
 val double = MutableStateFlow(1.8)
 int.combine(double){ i, d ->
            i + d             
 }.collect(::println)
于 2020-12-25T01:29:55.227 回答
0

合并 n 个状态流

@Suppress("CHANGING_ARGUMENTS_EXECUTION_ORDER_FOR_NAMED_VARARGS")
inline fun <reified T, R> combineStateFlow(
    vararg flows: StateFlow<T>,
    scope: CoroutineScope = GlobalScope,
    sharingStarted: SharingStarted = SharingStarted.Eagerly,
    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
        }
    }
}

要旨

于 2021-07-09T22:39:47.403 回答