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 获取导航控制器。