hi! what is the right way to use ViewModel with Co...
# compose-desktop
a
hi! what is the right way to use ViewModel with Compose Desktop? I've tried several times, but I always get
Copy code
No ViewModelStoreOwner was provided via LocalViewModelStoreOwner
for context, I've added
androidx.lifecycle:lifecycle-viewmodel-compose:2.8.3
as dependency, and also
org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.8.1
p
I think the right artifact is: "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", You may want to include the navigation library too, ViewModel on its own doesn't do much
thank you color 2
m
I am using this artifact, but I am still getting
No ViewModelStoreOwner was provided via LocalViewModelStoreOwner
. I've read the docs here: https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-viewmodel.html But I don't see anything I'm missing.
p
I think you have to import the navigation artifact, check here: https://github.com/MatkovIvan/nav_cupcake/blob/master/gradle%2Flibs.versions.toml#L8 But not sure if this one is needed too: lifecycle-runtime-compose = module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose"
m
It looks to be impossible: https://issuetracker.google.com/issues/336842920#comment2 You have to use
Compose UI 1.7.0-alpha05
, but the latest version on desktop is
alpha02
.
p
Oh I see, interesting. It seems we will have to wait for a bit. In the meantime versions in the project linked above work for desktop. There is an issue in Android tho 🤷‍♂️, similar to the one you linked.
i
> You have to use
Compose UI 1.7.0-alpha05
, but the latest version on desktop is
alpha02
. We're aligning only first two numbers in version (like 1.7) with Google. Compose Multiplatform 1.7.0-alpha02 is based on Google's 1.7.0-beta05. It's mentioned in release notes. But to make it work you don't need any alphas - combination with Compose 1.6.11 + Lifecycle 2.8.0 should work. If you're facing with 336842920 on Android - update (2.8.4) lifecycle on Android only. Just add Google's dependency to you androidMain source set. It works because JB library redirects to Google's binary on Android > similar to the one you linked Mentioned issue is not related to initial topic (view model is missed, not lifecycle). It should be provided by Compose UI since 1.6.10. So my only guess is - you're using older version of Compose.
👍 1
m
@Ivan Matkov It does not seem to be working for me. I am using: Compose
1.7.0-alpha2
org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0
org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.0
org.jetbrains.androidx.navigation:navigation-compose:2.8.0-alpha08
And getting
java.lang.IllegalStateException: CompositionLocal LocalLifecycleOwner not present
, just like in the issue I linked.
i
Android?
m
Desktop only
i
What Compose version do you use?
m
Copy code
1.7.0-alpha02
i
ah, sorry, I see
Please share the minimal reproduction project, I'll check
There are 2 "LocalLifecycleOwner" •
androidx.compose.ui.platform.LocalLifecycleOwner
androidx.lifecycle.compose.LocalLifecycleOwner
Which one do you use?
m
I see that file you linked provides
import androidx.lifecycle.compose.LocalLifecycleOwner
, my understanding is that the
org.jetbrains.androidx.lifecycle:lifecycle-*
packages expect
androidx.compose.ui.platform.LocalLifecycleOwner
, which is the source of the error.
i
No. "compose.ui.platform" is the old place, it's moved to lifecycle library in 1.7 with deprecation + redirection
Anyway. Both should work in 1.7. I'd like to look at reproduction project to understand your case
m
Then I'm not sure where is the incompatibility. I will try creating a minimal reproduction project later today.
👍 1
I got it working, turns out the
NavHost
composable has to be inside of a
Window
.
i
Right. We're providing the lifecycle of the window. I know that we have composable context outside, but since it's hard to match the multiwindow lifecycle to the state and I don't know the actual use case why it's needed, we didn't provide it for "application".
Do you want to use different windows in the same nav graph?
If so could you please file a feature request with use case explanation
m
No, in fact I didn't want to use navigation at all, but added it as a test to see if it fixes the problem. I only wanted to use ViewModel. I have now removed the
NavHost
and can see the ViewModel still works fine now that it's retrieved inside of a
Window
.
👍 1
I do have one application-level ViewModel though, and I guess I won't be able to migrate it to KMM ViewModel in that case.
i
You can provide your custom VM owner in any place
Copy code
private class ComposeViewModelStoreOwner: ViewModelStoreOwner {
    override val viewModelStore: ViewModelStore = ViewModelStore()
    fun dispose() { viewModelStore.clear() }
}

/**
 * Return remembered [ViewModelStoreOwner] with the scope of current composable.
 */
@Composable
private fun rememberViewModelStoreOwner(): ViewModelStoreOwner {
    val viewModelStoreOwner = remember { ComposeViewModelStoreOwner() }
    DisposableEffect(viewModelStoreOwner) {
        onDispose { viewModelStoreOwner.dispose() }
    }
    return viewModelStoreOwner
}
And set it via
Copy code
CompositionLocalProvider(LocalViewModelStoreOwner provides owner)
Or if you need it application wide, just use global object without any "remember" stuff
Please note that
ComposeViewModelStoreOwner
above should be more complicated for Android case - it needs to be backed up by system one to deal with their recreation stuff Or just use it as fallback like
LocalViewModelStoreOwner.current ?: rememberViewModelStoreOwner()
m
Thanks, I will try these 👍
👍 1
@Ivan Matkov Turns out I actually have a bunch of usages where I need the ViewModel outside of a Window, because the UI state I am collecting from the ViewModel is used to control the window (for example the window position). So I have 1 VM per Window, but I need the UI state to configure the window, and so need the VM before the Window is created. The way the Lifecycle/VM works seems suitable to apps where there is a single window, a NavHost inside, and different screens with VM's. In my application I have lots of smaller widgets each in separate windows, each "screen" is it's own Window, and one VM per Window.
i
Please file an feature request with description of your use case then. For the current version you can provide owners (like simple global ones) manually
622 Views