如何注入' memorbernavcontroller '从jetpack撰写到一个活动使用柄? &g



我想用柄把我的navHostController注入我的MainActivity。但是当我试图编译代码时,我得到以下错误:

> Task :app:kaptDebugKotlin
C:UserspierrAndroidStudioProjectsAndroidAppsComposeUdemycourse01crudappbuildgeneratedsourcekaptdebugcomexamplecrudCrudApplication_HiltComponents.java:129: error: [Dagger/MissingBinding] androidx.navigation.NavHostController cannot be provided without an @Inject constructor or an @Provides-annotated method.
public abstract static class SingletonC implements CrudApplication_GeneratedInjector,
^
androidx.navigation.NavHostController is injected at
com.example.crud.ui.MainActivity.navHostController
com.example.crud.ui.MainActivity is injected at
com.example.crud.ui.MainActivity_GeneratedInjector.injectMainActivity(com.example.crud.ui.MainActivity) [com.example.crud.CrudApplication_HiltComponents.SingletonC ? com.example.crud.CrudApplication_HiltComponents.ActivityRetainedC ? com.example.crud.CrudApplication_HiltComponents.ActivityC]
> Task :app:kaptDebugKotlin FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:kaptDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask$KaptExecutionWorkAction
> java.lang.reflect.InvocationTargetException (no error message)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/7.0.2/userguide/command_line_interface.html#sec:command_line_warnings
BUILD FAILED in 5s
24 actionable tasks: 2 executed, 22 up-to-date
这是我的MainActivity代码:
package com.example.crud.ui
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.navigation.NavHostController
import com.example.crud.navigation.NavigationComponent
import com.example.crud.ui.theme.CRUDTheme
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject lateinit var navHostController: NavHostController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CRUDTheme {
Surface(color = MaterialTheme.colors.background) {
NavigationComponent(navHostController)
}
}
}
}
}
这是我的NavigationModule代码:
package com.example.crud.di
import androidx.compose.runtime.Composable
import androidx.navigation.compose.rememberNavController
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
@Module
@InstallIn(ActivityComponent::class)
object NavigationModule {
@Composable
fun provideNavHostController() = rememberNavController()
}

这是NavigationComponent的代码(它将navHostController作为参数,我试图注入MainActivity):

package com.example.crud.navigation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.example.crud.ui.screens.crud.details.DetailScreen
import com.example.crud.ui.screens.crud.register.RegisterScreen
import com.example.crud.ui.screens.home.HomeScreen
import com.example.crud.ui.screens.home.HomeViewModel
@Composable
fun NavigationComponent(navController: NavHostController) {
NavHost(navController = navController, startDestination = Routes.HOME) {
composable(Routes.HOME) {
val homeViewModel: HomeViewModel = hiltViewModel()
val cities = homeViewModel.cities.observeAsState(listOf())
HomeScreen(
cities = cities,
navigateToDetailsAction = { navController.navigate(Routes.REGISTER) }
) { cityId ->
navController.navigate(Routes.getDetailsDynamicRoute(cityId))
}
}
composable(Routes.REGISTER) { RegisterScreen { navController.popBackStack() } }
composable(
route = Routes.DETAILS,
arguments = listOf(navArgument(Routes.CITY_ID_KEY) { type = NavType.IntType })
) { backStackEntry ->
val cityId = backStackEntry.arguments?.getInt(Routes.CITY_ID_KEY)
cityId?.let {
DetailScreen(cityId = it, popNavigation = { navController.popBackStack() })
}
}
}
}

我认为这与解决问题无关,但Routes.kt文件中的代码如下:

package com.example.crud.navigation
object Routes {
private const val DETAILS_BASE_ROUTE = "details/"
const val HOME = "home"
const val REGISTER = "register"
const val CITY_ID_KEY = "cityId"
const val DETAILS = "$DETAILS_BASE_ROUTE{$CITY_ID_KEY}"
fun getDetailsDynamicRoute(cityId: Int) = "$DETAILS_BASE_ROUTE${cityId}"
}

我做错了什么?

您可以将NavHostController包装在另一个类中实现此行为。这个Navigator类的作用域是你的MainActivity (ActivityRetainedComponent@ActivityRetainedScoped),并在记住它之后设置NavHostController。然后把它也注入到你的ViewModels中,你可以从那里导航。

/**
* Class to handle navigation. It should be injected into the screens' ViewModel
*/
class Navigator {
private var navController: NavHostController? = null
fun setController(controller: NavHostController) {
navController = controller
}
fun clear() {
navController = null
}
fun navigate() {
// TODO handle navigation with the navController
}
}

另外,记住注入一个由Navigator实现的接口,这样你就可以创建一个MockNavigator类来测试你的ViewModels

但是我认为你不需要在主类上创建NavController,因为这个部分的la类NavigationComponent我认为这个类是负责处理这个的

我是android世界的新手,但对我来说,NavigationComponent控制着NavController和它所有的交互是有意义的。

通常我这样使用

@Composable fun NavigationHost() {
val navController = rememberNavController()
MyTheme {
NavHost(
navController = navController,
NavItem.Main.route
)
{
composable(route = NavItem.Main.route) {
FeedScreen { productOnClick ->
navController.navigate(NavItem.Detail.createNavRoute(productOnClick.id))
}
}
composable(route = NavItem.Main.route) {
ConfirmationScreen {
navController.navigate(NavItem.Main.route)
}
}
}
}

}