I created a new composable activity project with the following dependencies:
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"
Then I created two composables, one with the Hilt's view model:
@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")
}
It works if I try to render them. However, when I add the 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()
}
}
}
}
}
}
}
My app crashes when I go to the screen 2 with the following error:
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
What am I doing wrong?
Full code:
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")
}
According to the document of 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.
To fix the issue we have two solutions:
viewModel()
from import androidx.lifecycle.viewmodel.compose.viewModel
hiltViewModel()
to the activity and pass to Screen2()
build.gradle
apply plugin: kotlin-kapt
kapt "com.google.dagger:hilt-android-compiler:2.40"
Create an extension of application and anotate with @HiltAndroidApp
and use in your app.