[英]Collect transformed StateFlow in Composable
There is function collectAsState()
applicable to a StateFlow
property in order to observe it in a Composable
.有适用于StateFlow
属性的 function collectAsState()
以便在Composable
中观察它。
A composable requires a StateFlow
because StateFlow
guarantees an initial value.可组合项需要StateFlow
,因为StateFlow
保证了初始值。 A Flow
doesn't come with that guarantee. Flow
没有这种保证。
Now, what is the way to go if I have a StateFlow
property but I want to apply an operator (like map
) before collecting the Flow
in the Composable
?现在,如果我有StateFlow
属性但我想在收集Composable
中的Flow
之前应用一个运算符(如map
),那么 go 的方法是什么?
Here an example:这里有一个例子:
Let's say a repository exposes a StateFlow<MyClass>
假设存储库公开了StateFlow<MyClass>
val myClassStateFlow: StateFlow<MyClass>
data class MyClass(val a: String)
... and a view model has a dependency on the repository and wants to expose only the property a
to its Composable
... ...和一个视图 model 依赖于存储库,并且只想将属性a
公开给它的Composable
...
val aFlow = myClassState.Flow.map { it.a } // <- this is of type Flow<String>
The map
operator changes the type from StateFlow<MyClass>
to Flow<String>
. map
运算符将类型从StateFlow<MyClass>
更改为Flow<String>
。
aFlow
has no initial value anymore? aFlow
不再具有初始值在语义上是否合理? After all its first emission is derived from the initial value of myClassStateFlow
.毕竟它的第一次发射是从myClassStateFlow
的初始值派生的。Flow
back into StateFlow
at some point.在某些时候需要将Flow
转换回StateFlow
。 Which is the more idiomatic place for this?哪个是更惯用的地方?
stateIn()
?在视图 model 中使用stateIn()
? How would the code look like?代码会是什么样子?collectAsState(initial: MyClass)
and come up with an initial value (although myClassStateFlow
had an initial value)?在可组合中使用collectAsState(initial: MyClass)
并得出一个初始值(尽管myClassStateFlow
有一个初始值)?See this issue on GitHub请参阅GitHub 上的此问题
Currently there is no built-in way to transform StateFlow
s, only Flow
s.目前没有内置的方法来转换StateFlow
s,只有Flow
s。 But you can write your own.但是你可以自己写。
Way I ended up solving was to use the example in that post.我最终解决的方法是使用该帖子中的示例。
First create a notion of a DerivedStateFlow
.首先创建一个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)
}
}
Then have an extension on StateFlow
like the current map
extension on Flow
然后在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) }
)
}
Now in your Repository or ViewModel, you can use it as below.现在在您的 Repository 或 ViewModel 中,您可以按如下方式使用它。
class MyViewModel( ... ) {
private val originalStateFlow:StateFlow<SomeT> = ...
val someStateFlowtoExposeToCompose =
originalStateFlow
.mapState { item ->
yourTransform(item)
}
}
Now you can consume it as you expect in Compose without any special work, since it returns a StateFlow
.现在,您无需任何特殊工作即可在 Compose 中按照您的预期使用它,因为它返回一个StateFlow
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.