【问题标题】:Collect transformed StateFlow in Composable在 Composable 中收集转换后的 StateFlow
【发布时间】:2022-01-06 12:46:01
【问题描述】:

有一个函数collectAsState()适用于StateFlow属性,以便在Composable中观察它。

可组合项需要StateFlow,因为StateFlow 保证了初始值。 Flow 不提供该保证。

现在,如果我有 StateFlow 属性但我想在收集 Composable 中的 Flow 之前应用运算符(如 map),该怎么办?

这里是一个例子:

假设存储库公开了StateFlow<MyClass>

val myClassStateFlow: StateFlow<MyClass>

data class MyClass(val a: String)

...并且视图模型依赖于存储库,并且只想将属性 a 公开给它的Composable...

val aFlow = myClassState.Flow.map { it.a } // <- this is of type Flow<String>

map 运算符将类型从 StateFlow&lt;MyClass&gt; 更改为 Flow&lt;String&gt;

  1. aFlow 不再具有初始值在语义上是否合理?毕竟它的第一次发射是从myClassStateFlow的初始值导出的。
  2. 有时需要将Flow 转换回StateFlow。哪个是更惯用的地方?
    1. 在视图模型中使用stateIn()?代码会是什么样子?
    2. 在可组合中使用collectAsState(initial: MyClass) 并得出一个初始值(虽然myClassStateFlow 有一个初始值)?

【问题讨论】:

    标签: android android-jetpack-compose kotlin-coroutines kotlin-stateflow


    【解决方案1】:

    this issue on GitHub

    目前没有内置的方法来转换StateFlows,只有Flows。但是你可以自己写。

    我最终解决的方法是使用该帖子中的示例。

    首先创建一个DerivedStateFlow 的概念。

    class DerivedStateFlow<T>(
        private val getValue: () -> T,
        private val flow: Flow<T>
    ) : StateFlow<T> {
    
        override val replayCache: List<T>
            get () = listOf(value)
    
        override val value: T
            get () = getValue()
    
        @InternalCoroutinesApi
        override suspend fun collect(collector: FlowCollector<T>) {
            flow.collect(collector)
        }
    }
    
    

    然后在StateFlow 上添加一个扩展名,就像在Flow 上的当前map 扩展名一样

    fun <T1, R> StateFlow<T1>.mapState(transform: (a: T1) -> R): StateFlow<R> {
        return DerivedStateFlow(
            getValue = { transform(this.value) },
            flow = this.map { a -> transform(a) }
        )
    }
    

    现在在您的 Repository 或 ViewModel 中,您可以按如下方式使用它。

    
    class MyViewModel( ... ) {
        private val originalStateFlow:StateFlow<SomeT>  = ...
        
        val someStateFlowtoExposeToCompose = 
            originalStateFlow
            .mapState { item -> 
                yourTransform(item)
            }
    }
    

    现在您无需任何特殊工作即可在 Compose 中按预期使用它,因为它返回 StateFlow

    【讨论】:

      猜你喜欢
      • 2022-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-17
      • 2022-01-18
      • 2022-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多