Hey is there a non-state version of `MutableStateF...
# flow
a
Hey is there a non-state version of
MutableStateFlow
? I have been using
ConflatedBroadcastChannel
, but would like to move to flow completely. I know there is
Flow
itself, but I have not found a way to send values to it from outside the creation lambda.
k
Can’t you just expose
MutableStateFlow
as
Flow
? The former one implements the latter, so you can do it by just casting
m
The problem is that MSF requires an initial value. Apart from converting a Channel into a Flow you can create your own AbstractFlow implementation 🤔 But behind the scenes many Flows are implemented using Channels, as they’re perfectly fine for that.
g
you also can just use StateFlow with initial null and filter it before returning from your class
m
Also good in cases where
null
is not a valid value. In that case you could make your own
val undefined = Any()
and filter that out.
a
So are Channels going to be deprecated in favor of
Flow
?
m
No, they still have their purpose.
Regarding a non-state Flow like
MutableStateFlow
note that here is another difference between using a Channel and a hidden `StateFlow`:
StateFlow
is conflating, i.e. it drops intermediate results if the collector is slow.
👍 1
a
So I guess using
ConflatedBroadcastChannel
and then calling
.asFlow()
would still be my best bet. Maybe I can wrap that in a version of
AbstractFlow
and call it
MutableFlow
to keep with the definitions.
m
What’s the use case btw?
a
The use case is Android state management. For View-State
MutableStateFlow
works perfectly fine, it’s a fantastic addition. But there are some things that should not be retained as states but still emitted (usually called effects), for example Toast messages (small messages shown once). For this a non-stateful
Flow
works, but it has to be able to be triggered from the outside. If you used
MutableStateFlow
for effects then you would show a toast message and then upon phone rotation would show the same toast message again, which is not required.
👍 2
AbstractFlow
is actually only for stateful
Flow
implementations:
Copy code
Base class for stateful implementations of `Flow`.
Would this be safe to do?
Copy code
private lateinit var effectsEmitter: FlowCollector<Effect>
    val effects = flow<Effect> {
        effectsEmitter = this
    }
m
Not really. You’d use
FlowCollector
from the wrong coroutine context and likely raise an exception.
Also, every new collector would overwrite the previous
effectsEmitter
. So if you have multiple collectors for the flow they break each other.
👍 1
a
I think this is probably the best approach then until there is some non-stateful official version of
Flow
Copy code
private val _effects = ConflatedBroadcastChannel<Effect>()
    val effects: Flow<Effect> = _effects.asFlow()
👍 1
m
Where are the Effects coming from? Why isn’t the source a Flow?
a
that’s good food for though. It could be anything. Could be a flow, could be a button click, could be some legacy code, could be some third party plugin.
m
Button clicks can also be flows 🙂
Looks like Channels stay but BroadcastChannels will go away. Upcoming change: "* Future deprecation notice for BroadcastChannel, ConflatedBroadcastChannel, broadcast, and broadcastIn."
a
Hmm so what could I replace the
ConflatedBroadcastChannel
in the example above with?
Still, we cannot rewrite everything to be a flow in a week, we need some layer in between 🙂
I found this: https://github.com/Kotlin/kotlinx.coroutines/issues/2034 Which looks like exactly what I need. Going to be released in 1.4.0
👍 1
g
Broadcast channels will be there for a quite long time, they not even deprecated yet