Jetpack compose如何集中navController并注入
Jetpack compose how to centralize navController and inject it
目前我的应用程序中有两个 NavGraphs
,一个用于身份验证路由,如登录和注册,另一个用于登录时的主页路由。
当我想使用它时,我目前需要在每个可组合项中将 navController
作为参数传递。这绝对是不可扩展的,所以我想知道是否有可能让它成为可注入的,这样我就可以通过像 Koin
这样的 DI 框架来请求它。我目前在我的应用程序中使用 Koin
,所以如果我可以使用它的依赖注入工具,将 navController
作为 singleton
.
注入,那就太好了
当前导航设置
我目前在 MainActifity
:
中创建了 navController
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavHostController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startKoin {
androidLogger(if (BuildConfig.DEBUG) Level.ERROR else Level.NONE)
androidContext(this@MainActivity)
modules(listOf(networkModule, viewModelModule, interactorsModule))
}
setContent {
navController = rememberAnimatedNavController()
SetupNavGraph(navController = navController)
}
}
}
然后我将它传递给包含两个 NavGraphs
:
的 NavHost
fun SetupNavGraph(
navController: NavHostController
) {
AnimatedNavHost(
navController = navController,
startDestination = AUTH_GRAPH_ROUTE,
route = ROOT_GRAPH_ROUTE
) {
homeNavGraph(navController = navController)
authNavGraph(navController = navController)
}
}
下面是我的 NavGraph
所有身份验证路由。我还将 NavController
作为参数传递,以便我可以在屏幕内使用它。
fun NavGraphBuilder.authNavGraph(
navController: NavController
) {
navigation(
startDestination = Screen.Login.route,
route = AUTH_GRAPH_ROUTE
) {
composable(
Screen.Login.route,
) {
val loginViewModel: LoginViewModel = getViewModel()
LoginScreen(
navController = navController,
state = loginViewModel.state.value,
onTriggerEvent = loginViewModel::onTriggerEvent
)
}
composable(
Screen.Register.route,
) {
val registerViewModel: RegisterViewModel = getViewModel()
RegisterScreen(
navController = navController,
state = registerViewModel.state.value,
onTriggerEvent = registerViewModel::onTriggerEvent
)
}
}
}
登录后所有页面的NavGraph
与我的授权相似,所以不值得展示。
如果我可以通过 Koin 创建一个 navController
作为 single
就好了,但这是不可能的,因为 rememberNavController
函数只能在 Composable 内部调用。
是否有任何解决方案可以解决将 navController
传递到每个嵌套可组合项的问题?
为了简单 testing/previewing,建议只传递处理程序而不是导航控制器本身,并在调用处理程序时在 SetupNavGraph
内进行所有真正的导航。可以找到更多信息 here。
如果它不适合你,你可以创建你自己的合成局部,像这样:
val LocalNavController = compositionLocalOf<NavHostController> {
error("No LocalNavController provided")
}
提供CompositionLocalProvider
:
setContent {
CompositionLocalProvider(LocalNavController provides rememberAnimatedNavController()) {
SetupNavGraph()
}
}
然后在 CompositionLocalProvider
内的任何可组合项中,您可以使用 LocalNavController.current
获取导航控制器。
目前我的应用程序中有两个 NavGraphs
,一个用于身份验证路由,如登录和注册,另一个用于登录时的主页路由。
当我想使用它时,我目前需要在每个可组合项中将 navController
作为参数传递。这绝对是不可扩展的,所以我想知道是否有可能让它成为可注入的,这样我就可以通过像 Koin
这样的 DI 框架来请求它。我目前在我的应用程序中使用 Koin
,所以如果我可以使用它的依赖注入工具,将 navController
作为 singleton
.
当前导航设置
我目前在 MainActifity
:
navController
class MainActivity : AppCompatActivity() {
private lateinit var navController: NavHostController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startKoin {
androidLogger(if (BuildConfig.DEBUG) Level.ERROR else Level.NONE)
androidContext(this@MainActivity)
modules(listOf(networkModule, viewModelModule, interactorsModule))
}
setContent {
navController = rememberAnimatedNavController()
SetupNavGraph(navController = navController)
}
}
}
然后我将它传递给包含两个 NavGraphs
:
NavHost
fun SetupNavGraph(
navController: NavHostController
) {
AnimatedNavHost(
navController = navController,
startDestination = AUTH_GRAPH_ROUTE,
route = ROOT_GRAPH_ROUTE
) {
homeNavGraph(navController = navController)
authNavGraph(navController = navController)
}
}
下面是我的 NavGraph
所有身份验证路由。我还将 NavController
作为参数传递,以便我可以在屏幕内使用它。
fun NavGraphBuilder.authNavGraph(
navController: NavController
) {
navigation(
startDestination = Screen.Login.route,
route = AUTH_GRAPH_ROUTE
) {
composable(
Screen.Login.route,
) {
val loginViewModel: LoginViewModel = getViewModel()
LoginScreen(
navController = navController,
state = loginViewModel.state.value,
onTriggerEvent = loginViewModel::onTriggerEvent
)
}
composable(
Screen.Register.route,
) {
val registerViewModel: RegisterViewModel = getViewModel()
RegisterScreen(
navController = navController,
state = registerViewModel.state.value,
onTriggerEvent = registerViewModel::onTriggerEvent
)
}
}
}
登录后所有页面的NavGraph
与我的授权相似,所以不值得展示。
如果我可以通过 Koin 创建一个 navController
作为 single
就好了,但这是不可能的,因为 rememberNavController
函数只能在 Composable 内部调用。
是否有任何解决方案可以解决将 navController
传递到每个嵌套可组合项的问题?
为了简单 testing/previewing,建议只传递处理程序而不是导航控制器本身,并在调用处理程序时在 SetupNavGraph
内进行所有真正的导航。可以找到更多信息 here。
如果它不适合你,你可以创建你自己的合成局部,像这样:
val LocalNavController = compositionLocalOf<NavHostController> {
error("No LocalNavController provided")
}
提供CompositionLocalProvider
:
setContent {
CompositionLocalProvider(LocalNavController provides rememberAnimatedNavController()) {
SetupNavGraph()
}
}
然后在 CompositionLocalProvider
内的任何可组合项中,您可以使用 LocalNavController.current
获取导航控制器。