Came across a sample app that contains this... thi...
# compose
c
Came across a sample app that contains this... this is bad... right? (or is the fact that it's somehow at the top level mean that it's "probably" safe because it won't recompose, therefore creating another HomeViewModel?
Copy code
setContent {
    MyTheme {
        val viewModel = HomeViewModel()
        HomeScreen(viewModel)
    }
}
Or at the very least the HomeViewModel creation should be wrapped in a
remember {}
?
j
This is bad because on config changes the viewmodel will be recreated.
I don't think
remember {}
would matter because on config changes I believe by default the Activity will be recreated so the entire composition will exist the View hiearchy.
I don't know if this is true for
isSystemInDarkTheme()
changes.
j
Don't understand why they didn't put that
val viewModel = HomeViewModel()
line before
setContent
j
Moving the viewmodel creation part wouldn't matter in the case of a config change on Android. Unless they have changed the default configChange policy in the manifest file.
e
which is recommended for a compose app
☝️ 1
j
I cannot find any recommendation here that activity recreation on configuration changes should be disabled for Compose apps.
To provide a good user experience, observe the following best practices:
Be prepared for frequent configuration changes: don't assume that configuration changes are rare or never happen, regardless of API level, form factor, or UI toolkit. When a user causes a configuration change, they expect apps to update and continue to work correctly with the new configuration.
Preserve state: don't lose the user's state when
Activity
recreation occurs. Preserve the state as described in Save UI states.
Avoid opting out as a quick fix: don't opt-out of
Activity
recreation as a shortcut to avoid state loss. Opting out of activity recreation requires you to fulfill the promise of handling the change, and you can still lose the state due to
Activity
recreation from other configuration changes, process death, or closing the app. It is impossible to entirely disable
Activity
recreation. Preserve the state as described in Save UI states.
Don't avoid configuration changes: don't put restrictions on orientation, aspect ratio, or resizability to avoid configuration changes and
Activity
recreation. This negatively impacts users who want to use your app in their preferred way.
Creating new a app in Android Studio does not alter that configuration for the default initial`MainActivity` .
j
That message is very old, and significantly before Jetpack Compose went stable. Is that still a valid recommendation? I cannot find any sources on developer.android.com
Seems odd that documentation specially says otherwise and Android Studio still generates projects using default config change policy if that is the official recommendation dating back to May 2021.
w
You can't actually catch every possible Activity recreation, although if you're writing good Compose, it shouldn't matter anyways. You should just use the state/retention APIs where appropriate and things will just work.
c
So seems like at the very least I should wrap it in a remember
e
if it's a viewmodel there's a registry that retains them over activity/fragment recreation, that you should retrieve them from. outside of setContent
using configChanges doesn't "matter" for compose in that the app should work correctly with our without them, but avoiding activity recreations will allow the app to have smoother transitions when configuration changes happen
j
@Colton Idle Yes.... But if you're on Android the better solution is to use this.
c
It's actually not an AAC viewmodel, just a plain ol class
j
Ah, then a
remember {}
should be fine as long as your disable activity recreation on config changes.
👍 1
e
or hoist it out of the composition and do state saving/restoration yourself
even if you disable all known configChanges, there still are a few that will cause activity recreation
1
j
You can also use
rememberSaveable {}
and the view model survive the activity or process recreation.
1
e
assuming it can be saved to a bundle, yeah. it's not typechecked
👍 1
w
What you really want is the yet to be merged
rememberRetained
, although you really should just be using the Android VM though, since it sets up a bunch of the owner/lifecycle/state stuff for you.
👀 1
☝️ 2
c
yeah. im doing some kmp/cmp stuff and came across this sample. and i was just like... double guessing myself on whether or not that was okay.
j
KMP supports ViewModels
On Android you still have the same Activity issue.
e
yep KMP viewmodel has been around since https://developer.android.com/jetpack/androidx/releases/lifecycle#2.8.0-alpha03 but only got into a stable release recently
c
i wonder if that works on desktop too
👌 2
p
Best is to use androidx ViewModel and everything that comes with it, lifecycle, saved-state, navigation and the different injection helpers functions
viewModel {ViewModelFactory}
. Also it is better to disable configuration changes, killing a whole Activity is a big waste of RAM potentially impacting phone energy. In case of process death, keep in mind the ViewModel will only be recreated with the saved state data aka serializable data. You will lose every state that is not serializable.
m
It's definitely bad IMHO. Along with the re-creation question, you have background / restore issues as well because there's no view model store associated with the view model. Ideally your vm factory would be injected into the activity with some di (dagger, koin, etc..). But if you do this as a property on the activity, you get proper view model store scoping to the activity with proper laziness, etc... as well as access to be able to create a savedStateHandle in the initializer
Copy code
val vm by viewModels<MyVM> { 
    viewModelFactory { 
        initializer { 
            MyVM()
        }
    }
}