How is everyone building ViewModels for compose de...
# compose-desktop
j
How is everyone building ViewModels for compose desktop?
m
I do it same as on Android. No need to have the
ViewModel
base class.
j
Okay, thanks. And then a data class for state with a private MutableStateFlow and a public read-only StateFlow + setter functions that the view can use?
a
pretty much, yes, the main feature of the ViewModel is to handle the lifecycle of the app
j
Cool. Are you using some kind of viewModelScope? For coroutines
(We are using compose for iOS GUI)
a
If you want you could use a library that provides what you need for that, I'm actually using moko-mvvm for it
You can also look here for more examples
a
Personally, I’m not using viewmodels at all.
👍 1
Just run the business logic directly from the UI.
💯 1
j
Yeah, I mean…. why not?
Why use ViewModels for multiplatform when there is no standard for it?
a
For multiplatform you may need to, so that it works correctly on Android. Although I’m not sure where the ViewModel would sit. It can’t be in shared module because it needs to subclass Android’s ViewModel.
But for desktop-only, you don’t have to.
j
I’m building for iOS, Android and desktop …. x)
a
You may need to do the VM via expect/actual
On Android wrap the non-Android (shared) VM in an Android VM
j
Hmm.. thanks
What if I don’t?
a
You could lose state when rotating the screen on Android
j
So… what if I disable screen rotation? 🙂
a
There are other configuration changes that can cause activity recreation
👍🏻 1
Maybe you can disable them too
j
Hmm
a
I haven’t written Android in a while so I’m not up do date on these things.
j
Okay thanks!
a
I roll my own viewmodels, which are just classes that are injected with the usecases and expose a stateflow and some methods. No frameworks needed and I’ve been bitten before by untestable business logic in UI. I have a simple composable called rememberViewModel which generates a viewModel from a DI context in the composition
z
Architectural layers definitely exist for a reason. But yea I would never use AAC ViewModels even on Android except where absolutely required.
h
@Zach Klippenstein (he/him) [MOD] what do you suggest as a remedy for the configuration change?
z
what do you suggest as a remedy for the configuration change?
Use an AAC VM at the root to hold the rest of your object graph, anchor your object graph in your app class, or save your entire graph via rememberSaveable. The latter might be hard to do, I’d probably go with one of the first two
a
@Zach Klippenstein (he/him) [MOD] this wasn’t in response to me right?
z
Edited my message to make it clear
j
Compose should handle most Android configuration change events without the need for activity recreation (anything that doesn't work would be a bug). So you should be able to disable activity recreation for all configuration change events, which decouples the need to use an Android
ViewModel
. Add this to your AndroidManifest.xml:
Copy code
<activity
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
    ...>
as the compose-multiplatform-template does. See this thread.
c
The AAC ViewModels class is mostly there as a workaround for difficulties in the app lifecycle, and while that doesn’t translate to Desktop, the general concept of a “view model” absolutely does. As other’s have mentioned, the analog of the AAC ViewModel in a Compose Desktop app is entirely about app architecture and how you want to manage the data. It’s basically just moving coroutines and state changes into another class for greater separation of concerns/testability. You can certainly keep your state changes directly in the Composition and run async code with
LaunchedEffect
or
rememberCoroutineScope()
, which is the easiest and fastest solution. But you can also use libraries which enforce specific patterns around managing state, like my Ballast MVI library, which can help wrangle that complexity as your app gets more interactive and it gets harder to manage properly in the composition alone.
a
Tbh, I couldn’t fathom how I’d make complex TESTABLE desktop apps without viewmodels
m
Right now I am following the basic ViewModel expect/actual in Android and React/JS as per https://github.com/touchlab/KaMPKit/blob/main/shared/src/commonMain/kotlin/co/touchlab/kampkit/models/ViewModel.kt I'm liking what I see in Voyager (Navigation library - includes a way to use https://github.com/adrielcafe/voyager
It has the concept of a "Screen Model" - which seems to do the same thing as a ViewModel. As a bonus, it provides navigation.
z
I use InstanceKeeper.Instance by Decompose Library which acts like Android's ViewModel. Works well with Android. No harm for other platforms https://arkivanov.github.io/Decompose/component/instance-retaining/#usage-example
decompose intensifies 1
The SomeLogic class in the example code above can be your ViewModel
a
Keep in mind that the AAC ViewModel on Compose is tied to the back stack, not just handling configuration changes. It not only survives configuration changes, but also stays alive while in the back stack.
👍 1
So you either use a multiplatform navigation library that provides ViewModel (or equivalent) API, or define expect/actual ViewModel (or use a library like moko-mvvm) plus platform navigation.
221 Views