【问题标题】:Cannot create viewmodel from composalbe function无法从 Composalbe 函数创建视图模型
【发布时间】:2021-04-22 07:04:38
【问题描述】:

我有一个视图模型。 我正在使用 Hilt。 我可以从活动中创建这个视图模型,就像这样

val model: ProfileViewModel by viewModels()

但是,当我尝试从可组合函数创建此视图模型时

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))
    }
}

我遇到错误

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

这是来自 Android 教程的 the example,但这对我不起作用。

【问题讨论】:

  • 您不能通过构造函数实例化 ViewModel 对象,创建对象有两种方法 1. 通过 ViewModelProviders & 2. val model: ProfileViewModel by viewModels() 扩展在 viewmodel-ktx 库中提供跨度>
  • ViewModel 绑定到视图生命周期
  • 在您的情况下,您可以使用这个 var 模型: ProfileViewModel = ViewModelProviders.of("activity-reference").get(ProfileViewModel::class.java)
  • 但在这个例子中,他们的做法和我一样developer.android.com/jetpack/compose/libraries#hilt

标签: dependency-injection viewmodel android-jetpack-compose


【解决方案1】:

因为我的可组合函数是通过导航而不是直接从 Fragment 或 Activity 创建的,所以我必须使用函数

hiltNavGraphViewModel()

详情在documentation

【讨论】:

  • 由于某种原因,在这种情况下,如果刀柄包含您的依赖项(通过@Module 提供),则它无法创建视图模型。例如,如果没有依赖项或使用 SavedStateHandle 依赖项,则不会出现创建错误。该文档具有误导性“如果...的范围限定为导航图”,如果不是,如果您需要完全限定为活动,那么错误来自哪里?错误?
  • 现在叫hiltViewModel()
【解决方案2】:

我用下面的方法解决了这个问题

class MyScreenManager(navController:NavigationController){

lateinit var viewModel:MyViewModel = HiltViewModelFactory(
            activity,
            navController.getBackStackEntry(MyScreen.route)
        ).create(MyViewModel::class.java)
}

上面的类没有被注入,而是从一个可组合函数导航到的

【讨论】:

    【解决方案3】:

    这是我的解决方案:

    步骤 1

    Project build.gradle 文件中,定义lifecycle_version = "2.4.0-beta01"

    // 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
    

    重要提示:它不适用于 androidx.lifecycle:lifecycle-livedata:2.3.1 及以下版本

    第二步

    app build.gradle 文件中,进行 3 处更改:(1) 更改为 compileSdk 31,(2) 更改为 targetSdk 31,以及 (3) 在 dependencies 中添加以下 implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"implementation "androidx.compose.runtime:runtime-livedata:$compose_version"

    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"
    }
    
    

    重要提示:它不适用于 compileSdk 30 和/或 targetSdk 30

    第三步

    确保导入androidx.lifecycle.viewmodel.compose.*

    import androidx.lifecycle.viewmodel.compose.*
    

    重要提示:必须包含上述导入

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-07
      • 1970-01-01
      • 2011-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-03
      相关资源
      最近更新 更多