'Cannot create viewmodel from composalbe function
I have a view model. I am using Hilt. I can create this view model from activity, like this
val model: ProfileViewModel by viewModels()
However when I try to create this view model from a composable function
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun ProfileScreen(){
val model: ProfileViewModel = viewModel()
Button(onClick = {
model.logout()
}){
Text(stringResource(R.string.log_out))
}
}
I am getting error
2021-04-22 10:01:55.503 10482-10482/com.pulsariodev E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.pulsariodev, PID: 10482
java.lang.RuntimeException: Cannot create an instance of class com.pulsario.ui.profile.ProfileViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:221)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:278)
at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:112)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.get(ViewModel.kt:78)
at androidx.lifecycle.viewmodel.compose.ViewModelKt.viewModel(ViewModel.kt:63)
at com.pulsario.ui.profile.ProfileScreenKt.ProfileScreen(ProfileScreen.kt:23)
at com.pulsario.ui.main.MainScreenKt$MainScreen$2$1$1$1.invoke(MainScreen.kt:60)
at com.pulsario.ui.main.MainScreenKt$MainScreen$2$1$1$1.invoke(MainScreen.kt:59)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:118)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.navigation.compose.NavHostKt$NavHost$5$1$1.invoke(NavHost.kt:138)
at androidx.navigation.compose.NavHostKt$NavHost$5$1$1.invoke(NavHost.kt:137)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:193)
at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:84)
at androidx.navigation.compose.NavHostKt.SaveableStateProvider(NavHost.kt:150)
at androidx.navigation.compose.NavHostKt.access$SaveableStateProvider(NavHost.kt:1)
at androidx.navigation.compose.NavHostKt$NavHost$5$1.invoke(NavHost.kt:137)
at androidx.navigation.compose.NavHostKt$NavHost$5$1.invoke(NavHost.kt:136)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:193)
at androidx.navigation.compose.NavHostKt.NavHost(NavHost.kt:132)
at androidx.navigation.compose.NavHostKt$NavHost$6.invoke(Unknown Source:13)
at androidx.navigation.compose.NavHostKt$NavHost$6.invoke(Unknown Source:10)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:97)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2117)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2375)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:2517)
at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:2488)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:546)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:733)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:102)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:443)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:415)
at androidx.compose.ui.platform.AndroidUiFrameClock$withFrameNanos$2$callback$1.doFrame(AndroidUiFrameClock.android.kt:34)
at androidx.compose.ui.platform.AndroidUiDispatcher.performFrameDispatch(AndroidUiDispatcher.android.kt:109)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performFrameDispatch(AndroidUiDispatcher.android.kt:41)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:69)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:965)
at android.view.Choreographer.doCallbacks(Choreographer.java:791)
2021-04-22 10:01:55.504 10482-10482/com.pulsariodev E/AndroidRuntime: at android.view.Choreographer.doFrame(Choreographer.java:722)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:952)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7386)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
Caused by: java.lang.InstantiationException: java.lang.Class<com.pulsario.ui.profile.ProfileViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:219)
... 52 more
Here is the example from Android tutorial but this does not work for me.
Solution 1:[1]
Because my composable function is created via navigation but not directly from Fragment or Activity I have to use the function
hiltViewModel()
Details in the documentation
Solution 2:[2]
I solved this using the below
class MyScreenManager(navController:NavigationController){
lateinit var viewModel:MyViewModel = HiltViewModelFactory(
activity,
navController.getBackStackEntry(MyScreen.route)
).create(MyViewModel::class.java)
}
The above class was not injected but navigated to from a composable function
Solution 3:[3]
Here's my solution:
Step 1
In the Project build.gradle
file, define lifecycle_version = "2.4.0-beta01"
as in
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
compose_version = '1.0.1'
lifecycle_version = "2.4.0-beta01"
}
// rest is the same
Important: It won't work with androidx.lifecycle:lifecycle-livedata:2.3.1 and probably below
Step 2
In the app build.gradle
file, make 3 changes: (1) change to compileSdk 31
, (2) change to targetSdk 31
, and (3) add to dependencies
the following implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
and implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
as in
android {
compileSdk 31
defaultConfig {
minSdk 21
targetSdk 31
//rest is the same
}
}
//rest is the same
dependencies {
//...
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
}
Important: It won't work with compileSdk 30 and/or targetSdk 30
Step 3
Make sure to import androidx.lifecycle.viewmodel.compose.*
import androidx.lifecycle.viewmodel.compose.*
Important: Must include the above import
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Cyber Avater |
Solution 2 | D Lad |
Solution 3 |