Is there a reason to expose properties in a viewmo...
# compose
a
Is there a reason to expose properties in a viewmodel as
StateFlow
rather than just state values (e.g. by
by mutableStateOf
)?
f
a
Ok, so I guess the answer is “not unless you have a specific reason”
f
The answer is
You should use the thing that most suits your project and codestyle
😄 Use whatever you feel like using. There is no "problem" with either approach
a
Got it, thanks
I think for me state values win because I don’t have to have two flow fields for each property.
and no
_foo
ugliness
f
While I personally agree with your solution, you should bear in mind that the Android documentation suggests using one data holder for all your data so you shouldn't have multiple properties.
a
Can you point me to that? Seems strange and would cause unnecessary recompositions.
m
One difference is that
StateFlow
is a pure Kotlin concept and does not depend on the compose framework but
mutableStateOf
is not. So if you want to keep your models pure it is better to follow the guidelines. In general it is not a good idea trying to be smarter than the inventors of a technology.
🚫 1
f
Can you point me to that? Seems strange and would cause unnecessary recompositions.
https://developer.android.com/jetpack/guide/ui-layer#define-ui-state
a
@Michael Paus I understand that, but it seems too puritanical for me. The models are View models, so I don’t think it’s such a big deal to have them depend on compose. Moreover, I was told the state/snapshot stuff in compose is completely separate from all the UI library.
👌 1
f
One difference is that
StateFlow
is a pure Kotlin concept and does not depend on the compose framework but
mutableStateOf
is not. So if you want to keep your models pure it is better to follow the guidelines.
It is suggested in Adroid guidelines that you can use Compose State when building your app with Compose UI:
In Jetpack Compose apps, you can use Compose's observable State APIs such as
mutableStateOf
or
snapshotFlow
for the exposure of UI state. Any type of observable data holder such as
StateFlow
or
LiveData
that you see in this guide can be easily consumed in Compose using the appropriate extensions.
m
For me this distinction is important because I can then drive a JavaFX GUI with the exact same view model that I use for the Compose GUI.
a
If you have
StateFlow
in your viewmodel, you need to convert it to a compose state via
StateFlow.collectAsState
to be able to use in in compose UI. If you have compose state in your viewmodel, you need to convert it to a flow via
snapshotFlow
to be able to use it in JavaFX UI. Seems symmetrical. No?
1
@Filip Wiesner This is the relevant paragraph?
UI states: single stream or multiple streams? The key guiding principle for choosing between exposing UI state in a single stream or in multiple streams is the previous bullet point: the relationship between the items emitted. The biggest advantage to a single-stream exposure is convenience and data consistency: consumers of state always have the latest information available at any instant in time. However, there are instances where separate streams of state from the ViewModel might be appropriate:
Unrelated data types: Some states that are needed to render the UI might be completely independent from each other. In cases like these, the costs of bundling these disparate states together might outweigh the benefits, especially if one of these states is updated more frequently than the other.
UiState
diffing:
The more fields there are in a
UiState
object, the more likely it is that the stream will emit as a result of one of its fields being updated. Because views don’t have a diffing mechanism to understand whether consecutive emissions are different or the same, every emission causes an update to the view. This means that mitigation using the
Flow
APIs or methods like
distinctUntilChanged()
on the
LiveData
might be necessary.
Compose does have a diffing mechanism, though.
But I think it will still result in some unnecessary recompositions
m
@Alexander Maryanovsky In the second case my JavaFX application has an unwanted dependency on the Compose framework.
l
One use case for using Flows instead is KMM. I use ViewModels for both iOS and Android. iOS doesn’t support compose currently, so if my ViewModels use state, I can’t use them in iOS. I generally prefer to expose a flow that I can collectAsState, so it will work with both Compose, which supports state and SwiftUI, which does not.
1