Given the following viewmodel: ```class ViewModel ...
# android
o
Given the following viewmodel:
Copy code
class ViewModel {
    val selectedColor: Flow<Color> = ...
    fun onNewColorSelect(newColor: Color) {
        ...
    }
}
How can the
onNewColorSelect
method update the selectedColor flow? With Android, you would use MutableLiveData. How would you solve this problem with Flow?
z
It depends how your create your flow. The most common way is to use a
BroadcastChannel
or
ConflatedBroadcastChannel
and convert it into a
Flow
using
asFlow()
. Then you can
offer
values to the channel and they will be emitted.
👍 1
m
Copy code
private val colorBroadcastChannel = ConflatedBroadcastChannel<Color>

val selectedColor: Flow<Color> = colorBroadcastChannel.asFlow()

fun onNewColorSelect(newColor: Color) {
    colorBroadcastChannel.offer(color)
}
z
you probably want to make the channel property private, but yea that’s the idea
👍 1
m
yes, I've forget that, this is only a sample
o
Really helpful guys, thanks. Is there a reason why one would still expose
selectedColor
as a
Flow<Color>
instead of a
ConflatedBroadcastChannel<Color>
?
m
to external users of your ViewModel don't manipulate it, offering new values... encapsulation...
o
Ah I see, didn't realise
ConflatedBroadcastChannel<T>
is also write-able
m
yes, this is only for the encapsulation
z
Mostly encapsulation, but also it’s just a nicer API: `Channel`s are effectively a low-level communication primitive and aren’t meant to chain/transform (most/all operators on channels are deprecated). Exposing a
Flow
immediately gives your consumers access to all the flow operators.
m
yes, also this ☝️
o
Thanks, any reason why I would use
.offer()
over
.send()
?
z
send()
is a suspend function, so you can’t call it directly from
onNewColorSelect()
but for
ConflatedBroadcastChannel
, the effect is always the same (
send
never suspends,
offer
always returns
true
)
o
Cool, so does that mean I should expose streams as
Flow<T>
, but should not use the
flow
operator? For example, if I want to initialize the selectedColor Flow with a suspending
getRemoteColor()
function.
m
flow
creates a
Flow
that completes (or close) when the it hits its finish like:
Copy code
flow<MyObj> {
   doOperation1()
   doOperation2()
   ... // after this line this flow will close
}
this is "like" a hot operator for Flows
this is a good start point
o
Thanks,I try to read throughout it alot. What I still can't wrap my head around is the difference between
.map()
vs
.transform()
.
z
map
is a special case of
transform
, if you always want to emit exactly one downstream value for each upstream value:
Copy code
fun <T, R> Flow<T>.map(
  mapper: suspend (T) -> R
): Flow<R> = transform { emit(mapper(it)) }