If I'm using multiple MutableStateFlow instance fi...
# compose
y
If I'm using multiple MutableStateFlow instance fields for individual settable options of a composable, then using collectAsState inside the composable. Is there any guidance as to whether to use 6 individual fields, vs a single combined field with a data class. Do 6 State instances (of primitives, like Int / String) perform worse than a single State instance with that data class.
I guess second question is if it's new code but stored as a instance field, can I swap between MutableStateFlow and mutableStateOf()? Is there much difference?
c
Personally i would not use
mutableStateOf()
in a ViewModel. Compose specific code should not leak into VMs.
StateFlow
is a better fit there.
👎🏼 1
👍 2
👍🏻 1
👎 4
UIState object vs. multiple fields is an old debate, i do not think there is a consensus. 🙂 Performance wise, there should not be any difference, since you already read these 6 different streams, combining them into an object is not expensive.
👍🏻 1
m
I think he was asking about performance in like which ones minimize recompositions, rather than what is costly in creation of the flow.
c
Sorry, i missed that. The combined class could be suboptimal in that case, since if any of its 6 field change, the whole object will change, and compose has to recompose everything which reads the state object.
👍 1
👍🏻 1
a
Prefer snapshot state, that is,
mutableStateOf
. Yes, in ViewModels too. Snapshots are not a UI or Compose-specific technology, it's a generic observable MVCC system.
😮 1
Multiple MutableStateFlows mean you can't ensure consistency across them in a thread-safe way. Single UiState objects in MutableStateFlows mean you're doing very broad recompositions from the root whenever things change instead of granular recompositions of only the things that change, and repeated .equals comparisons made by compose on stable objects can traverse large sections of that object tree multiple times as recomposition proceeds downward if you don't hit all the right optimization cases. Copying deep immutable object trees to make a change is cumbersome and usually means you're introducing something like arrow lenses to make it less obnoxious. Snapshots were literally created to solve these problems. Stop worrying what maven artifact they're delivered in and use them. 🙂
😮 1
👍 2
1
👍🏻 1
😐 1
c
@Adam Powell How about decoupling the VM from the UI lifecycle. In this article we can see a way how to collect Flows from a VM in compose that respects the view lifecycle. If the Snapshot states are created in the VM how is it possible to handle lifecycle correctly without the VM knowing about it explicitly?
a
If you are truly using cold data sources then that matters, but if you have hot data sources (if you're using
MutableStateFlow
those are hot data sources) then doing any sort of lifecycle-bound collect isn't buying you much, if anything. Whatever process is changing the MutableStateFlow in response to other external stimuli is still running in the background unless you have some different means of limiting it.
c
I am not sure I can follow the reasoning perfectly. Can you show any code as reference, where snapshot state is created in the ViewModels. Did I miss a Compose sample app that does this?
a
It's the same as any of the hoisted state samples, just in a class that extends ViewModel.
Copy code
class MyViewModel : ViewModel() {
  var myValue by mutableStateOf(initial)
    private set // optional
}
a
@Adam Powell I am not sure if I understood it correctly. In the original question of whether to use UIState object vs. multiple fields, is it correct to assume that having multiple fields with snapshot state is better? I’ve been working on Kotlin Multiplatform Projects where we share ViewModel across platform and so we do not use
mutableStateOf
inside the ViewModel. Is this assumption correct?
106 Views