Search code examples
kotlinandroid-jetpack-composeandroid-viewmodel

Create a sharedViewModel within a separate module nav graph (Compose)


I'm trying to create an instance of a shared view model (that uses hilt), to share between my 2 composable "screens", both of them are in a separate graph (because of nested navigation) and I cannot find a way to create the view model (and making the instance in the other module seems... just awfully wrong)

code:

main navigation inside MainActivity

Surface(
    modifier = Modifier.fillMaxSize(),
    color = MaterialTheme.colors.background
) {
    // I technically could create the viewModel instance here, but that seems awful!
    val mainNavController = rememberNavController()
    NavHost(
        navController = mainNavController,
        startDestination = ProductRoutes.ProductGraph.route
    ) {
        productGraph(navController = mainNavController)
    }
}

ProductGraph:

fun NavGraphBuilder.productGraph(
    navController: NavController
) {
    navigation(
        startDestination = ProductRoutes.ProductListScreen.route,
        route = ProductRoutes.ProductGraph.route
    ) {
        composable(route = ProductRoutes.ProductListScreen.route) {
            ProductListScreen(navController = navController)
        }

        composable(
            route = ProductRoutes.ProductDetailScreen.route
        ) {
            ProductDetailScreen(navController = navController)
        }
        // both need the same view model to pass a product to display (from the list to detail screen)
    }
}

I'm looking for ways to create the VM in a reasonable way in this scenario

Any tips / hints / gists will be appreciated, thanks :)


Solution

  • I think we can get the view model from the using the navBackEntry, it will only work if don't pop your previous navGraph on navigating to the other.

     navigation(
            startDestination = ProductRoutes.ProductListScreen.route,
            route = ProductRoutes.ProductGraph.route
        ) {
    
            composable(route = ProductRoutes.ProductListScreen.route) {
                val parentEntry = remember {
            navController.getBackstackEntry("the route to your previous nav 
                    graph")
              }
              val vm = viewModel<ViewModelClass>(parentEntry)
                ProductListScreen(navController = navController)
            }
    
            composable(
                route = ProductRoutes.ProductDetailScreen.route
            ) {
                ProductDetailScreen(navController = navController)
            }
            // both need the same view model to pass a product to display (from the list to detail screen)
        }