frankelot
07/08/2021, 2:01 PM.map
on a StateFlow
returns a Flow
?iamthevoid
07/08/2021, 2:02 PM.map
defined as extension to Flow
?frankelot
07/08/2021, 2:03 PM.map
a StateFlow and still keep it a StateFlowiamthevoid
07/08/2021, 2:05 PMmap
that creates new instance of StateFlow
and return it explicitlyFlow
, just flow), so it must be referenced to Flow
abstraction and returns Flow
, but not an subtype of Flow
frankelot
07/08/2021, 2:11 PMclass MainViewModel {
val sf : StateFlow = ...
fun observeFooEvents() : StateFlow = sf.map { it is Foo }
fun observeBarEvents() : StateFlow = sf.map { it is Bar }
}
iamthevoid
07/08/2021, 2:13 PMFlow
from these functionsobserveFooEvents
and observeBarEvents
must don’t care about kind of abstraction in your ViewModelfrankelot
07/08/2021, 2:16 PMviewModel.observeBarEvents.collectAsState(initial = ???)
collectAsState
doesn’t ask for an initial stateiamthevoid
07/08/2021, 2:17 PMfrankelot
07/08/2021, 2:17 PMiamthevoid
07/08/2021, 2:18 PMfrankelot
07/08/2021, 2:19 PMiamthevoid
07/08/2021, 2:21 PMfun <T, R> StateFlow<T>.observeAsState(mapper: (T) -> R) {
return map(mapper).observeAsState(mapper(value))
}
frankelot
07/08/2021, 2:27 PMvalue
in this case?iamthevoid
07/08/2021, 2:27 PMAdam Powell
07/08/2021, 2:31 PM...
in val sf : StateFlow = ...
?MutableStateFlow
or other hot data source you might be better off using snapshot state here instead of StateFlows. More conversation on this specific use case here: https://github.com/Kotlin/kotlinx.coroutines/issues/2631louiscad
07/08/2021, 2:33 PMmap
returns a Flow
no matter what because its lambda can suspend. The best it could statically do, unless you can have non suspending lambda overloads, is return a SharedFlow
.Adam Powell
07/08/2021, 2:35 PMfrankelot
07/08/2021, 2:36 PMvalue
is accessible! but collectAsState
is only available on a Composable
context
@Adam Powell
…
is a MutableStateFlow
in deed. Will explore using SnapShotstate insteadiamthevoid
07/08/2021, 2:36 PM@Composable
annotation to your function🤷frankelot
07/08/2021, 2:38 PMiamthevoid
07/08/2021, 2:40 PMAdam Powell
07/08/2021, 2:41 PMMutableStateFlow
then using snapshot state instead this simplifies to:
class MainViewModel {
var source by mutableStateOf(...)
private set
val isFoo: Boolean get() = source is Foo
val isBar: Boolean get() = source is Bar
}
any reads of isFoo
or isBar
are observable. Instead of using collectAsState
you can just write vm.isFoo
without any special collect calls or mapping operatorsget() =
parts in that example though 🙂 )frankelot
07/08/2021, 2:45 PMmutableStateOf
instead will see how it goesAdam Powell
07/08/2021, 2:46 PMfrankelot
07/08/2021, 3:09 PMmutableStateOf
won’t cut it for me either (I think)
The example I show above is not actually what I’m doing, this is what I’m actually doing
class MainVm {
val stateFlow = ...
val fooHandler = FooHandler(stateFlow.map { it is Foo })
val batHandler = BarHandler(stateFlow.map { it is Bar })
}
Adam Powell
07/08/2021, 3:10 PM() -> Boolean
, leading to
val fooHandler = FooHandler({ state is Foo })
but what other support you might want/need depends on what else FooHandler does with itfrankelot
07/08/2021, 3:15 PMval filterFlow: StateFlow<Map<FILTER, FloatArray>>
Each contextual gets passed a set of filters (it’s an image editing app)LightContextual
gets passed down “EXPOSURE” “BRIGHTNESS”Adam Powell
07/08/2021, 3:19 PMfrankelot
07/08/2021, 3:21 PMstateIn
.. I was trying something outAdam Powell
07/08/2021, 3:24 PMfrankelot
07/08/2021, 3:24 PMAdam Powell
07/08/2021, 3:32 PMopen class SliderContextualViewModel(
private val getFilters: () -> Map<FILTER, FloatArray>,
val onFilterChanged: (FILTER, FloatArray) -> Unit,
val onFilterCommitted: () -> Unit = {}
) {
val filters: Map<FILTER, FloatArray>
get() = getFilters()
}
then use it like
// note: mutableStateMapOf is a snapshot state map
private var appliedFilters = mutableStateMapOf<FILTER, FloatArray>()
val lightContextualViewModel = SliderContextualViewModel(
onFilterChanged = ::onValueChanged,
getFilters = { appliedFilters.filterKeys { listOf(FILTER.EXPOSURE, FILTER.GRAIN, FILTER.VIBRANCE).contains(it) } },
onFilterCommitted = history::onCommit
)
Manuel Vivo
07/08/2021, 4:12 PMmutableStateOf
instead of `StateFlow`/`LiveData`. If you’re not working on a hybrid screen, using the latter makes no sense to me 🙂frankelot
07/08/2021, 4:36 PMprivate val getFilters: () -> Map<FILTER, FloatArray>
Adam Powell
07/08/2021, 4:40 PMfrankelot
07/08/2021, 6:27 PMViewModel-like class that holds the UI state using@Manuel Vivo what do you mean by hybrid in this context?instead of `StateFlow`/`LiveData`. If you’re not working on a hybrid screen, using the latter makes no sense to memutableStateOf
Manuel Vivo
07/08/2021, 7:24 PMStateFlow
or LiveData
. So if you’re mixing both approaches, you could also consume that stream for Compose. But if you’re in a Compose-only screen, you could just use the Compose State APIs.frankelot
07/08/2021, 7:58 PM