Jetpack 使用 HiltViewModel 组合导航:MainActivity 未实现接口 dagger.hilt.internal.GeneratedComponent

Jetpack Compose Navigation with HiltViewModel: MainActivity does not implement interface dagger.hilt.internal.GeneratedComponent

我创建了一个新的可组合 activity 项目,具有以下依赖项:

implementation "androidx.navigation:navigation-compose:2.4.0-alpha09"
implementation "com.google.dagger:hilt-android:2.38.1"
implementation "androidx.hilt:hilt-navigation-compose:1.0.0-alpha03"

然后我创建了两个可组合项,一个带有 Hilt 的视图模型:

@Composable
fun Screen1(onClick: () -> Unit) {
    Column {
        Text(text = "Screen 1")
        Button(onClick = onClick) {
            Text("To Screen 2")
        }
    }
}

@HiltViewModel
class Screen2ViewModel @Inject constructor() : ViewModel()

@Composable
fun Screen2(viewModel: Screen2ViewModel = hiltViewModel()) {
    Text(text = "Screen 2")
}

如果我尝试渲染它们,它会起作用。但是,当我添加 NavController:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val navController = rememberNavController()

            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    NavHost(navController = navController, startDestination = "screen1") {
                        composable("screen1") {
                            Screen1() {
                                navController.navigate("screen2")
                            }
                        }
                        composable("screen2") {
                            Screen2()
                        }
                    }
                }
            }
        }
    }
}

当我转到屏幕 2 时,我的应用程序崩溃并出现以下错误:

java.lang.IllegalStateException: Given component holder class com.sample.myapplication.MainActivity does not implement interface dagger.hilt.internal.GeneratedComponent or interface dagger.hilt.internal.GeneratedComponentManager

我做错了什么?

完整代码:

package com.sample.myapplication

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.sample.myapplication.ui.theme.MyApplicationTheme
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val navController = rememberNavController()

            MyApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(color = MaterialTheme.colors.background) {
                    NavHost(navController = navController, startDestination = "screen1") {
                        composable("screen1") {
                            Screen1() {
                                navController.navigate("screen2")
                            }
                        }
                        composable("screen2") {
                            Screen2()
                        }
                    }
                }
            }
        }
    }
}

@Composable
fun Screen1(onClick: () -> Unit) {
    Column {
        Text(text = "Screen 1")
        Button(onClick = onClick) {
            Text("To Screen 2")
        }
    }
}

@HiltViewModel
class Screen2ViewModel @Inject constructor() : ViewModel()

@Composable
fun Screen2(viewModel: Screen2ViewModel = hiltViewModel()) {
    Text(text = "Screen 2")
}

只需确认您在 Activity 上添加了 @AndroidEntryPoint 注释,在 ViewModel 上添加了 @HiltViewModel 注释。

这两个更新将解决此问题。

根据HiltViewModel

的文档

Returns an existing HiltViewModel -annotated ViewModel or creates a new one scoped to the current navigation graph present on the {@link NavController} back stack. If no navigation graph is currently present then the current scope will be used, usually, a fragment or an activity.

要解决此问题,我们有两个解决方案:

  1. 使用 import androidx.lifecycle.viewmodel.compose.viewModel
  2. 中的 viewModel()
  3. hiltViewModel() 的实例范围限定到 activity 并传递给 Screen2()
  4. 需要应用 Hilt 插件作为下一个答案: 向应用添加更多内容 build.gradle
  • apply plugin: kotlin-kapt
  • 将刀柄 android 编译器添加到依赖项 kapt "com.google.dagger:hilt-android-compiler:2.40" 创建应用程序的扩展并使用 @HiltAndroidApp 进行注释并在您的应用程序中使用。

应用 @AndroidEntryPoint 注释本身不会执行任何操作 - 它是一个标记注释,允许 Hilt Gradle Plugin 处理您的代码并生成使 Hilt 正常工作所需的正确字节码。您需要确保插件已应用:

buildscript {
  repositories {
    // other repositories...
    mavenCentral()
  }
  dependencies {
    // other plugins...
    classpath 'com.google.dagger:hilt-android-gradle-plugin:2.40'
  }
}
apply plugin: 'com.android.application'
apply plugin: 'dagger.hilt.android.plugin'

android {
  // ...
}