Mark
12/30/2023, 5:58 AMFlow to a StateFlow without using a CoroutineScope. The idea is that the underlying Flow is only collected when the StateFlow is collected. Before that, the StateFlow would just act as an initial state holder. Is this possible?Sam
12/30/2023, 9:49 AMMutableStateFlow. In the upstream flow, add an onEach block that updates the MutableStateFlow.Sam
12/30/2023, 9:50 AMefemoney
12/30/2023, 9:51 AMStateFlow subclass. (even though its not “safe” for extesion)efemoney
12/30/2023, 9:52 AMclass 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>): Nothing {
flow.distinctUntilChanged().conflate().collect(collector)
awaitCancellation()
}
}
(credit @billjings)Mark
12/30/2023, 10:02 AMgetValue() here. It seems to be totally unrelated to flow. I would expect an initialValue: T to be passed in. And the collect() to return that value first. value would initially return initialValue and then the values as collected from flow.efemoney
12/30/2023, 10:03 AMefemoney
12/30/2023, 10:06 AM{ otherStateFlow.map{…} }. )Mark
12/30/2023, 10:06 AMclass DerivedStateFlow<T>(
private val initialValue: T,
private val flow: Flow<T>,
) : StateFlow<T> {
override val replayCache: List<T>
get() = listOf(_value)
private var _value: T = initialValue
override val value: T
get() = _value
override suspend fun collect(collector: FlowCollector<T>): Nothing {
flow {
emit(initialValue)
emitAll(flow)
}.distinctUntilChanged()
.conflate()
.onEach { _value = it }
.collect(collector)
awaitCancellation()
}
}franztesca
12/30/2023, 12:08 PMMark
12/30/2023, 2:05 PMMutableStateFlow is in this case. Surely you would want a StateFlow only, in which case just use stateInfranztesca
01/01/2024, 11:51 AMBefore that, theIf you don't need it to be mutable, then using the built-inwould just act as an initial state holderStateFlow
stateIn sounds like a better option.Mark
01/02/2024, 3:23 AMby) can lead to uiStateState . Or is that just me?uli
01/02/2024, 11:14 AMclass FlowStateFlow<T> private constructor(
private val flow: Flow<T>,
private val stateFlow: MutableStateFlow<T>,
) : StateFlow<T> by stateFlow {
constructor(
flow: Flow<T>,
initial: T,
) : this(flow, MutableStateFlow(initial))
override suspend fun collect(collector: FlowCollector<T>): Nothing {
coroutineScope {
launch {
flow.collect {
stateFlow.value = it
}
}
stateFlow.collect {
collector.emit(it)
}
}
}
}
You might want to launch on Dispatchers.Default to collect the original flow in the background. I am just not sure if it is worth it. Would be interesting to see the behaviour under load.