admin管理员组

文章数量:1025227

I'm working with Jetpack Compose and Hilt for dependency injection in a nested navigation setup. I need to share a ViewModel (specifically, nested_home ViewModel) between a nested screen (NestedHomeScreen) and its parent screen (HomeScreen). Both screens are part of different navigation graphs, but I want the HomeScreen to be able to access the same ViewModel instance used in NestedHomeScreen.

@Composable
fun MainNavGraph(navController: NavHostController) {
    NavHost(navController = navController, startDestination = "home") {
        composable("home") { HomeScreen(navController) }
        composable("profile") { ProfileScreen(navController) }
        composable("nested_container") { NestedContainerScreen(navController) }
    }
}

@Composable
fun NestedContainerScreen(navController: NavHostController) {
    // Create a nested NavController for the subgraph
    val nestedNavController = rememberNavController()

    // Nested NavHost as the subgraph
    NavHost(navController = nestedNavController, startDestination = "nested_home") {
        composable("nested_home") {
            NestedHomeScreen(nestedNavController)
        }
        composable("nested_detail/{id}") { backStackEntry ->
            val id = backStackEntry.arguments?.getString("id")
            NestedDetailScreen(id = id)
        }
    }
}

val nestedHomeViewModel : HomeViewModel = hiltViewModel()

//need to access it in parent nav host home screen

Note:

  1. Do not use global scope viewmodel to parent navhost to share
  2. Do not use subgraph using navigation

I'm working with Jetpack Compose and Hilt for dependency injection in a nested navigation setup. I need to share a ViewModel (specifically, nested_home ViewModel) between a nested screen (NestedHomeScreen) and its parent screen (HomeScreen). Both screens are part of different navigation graphs, but I want the HomeScreen to be able to access the same ViewModel instance used in NestedHomeScreen.

@Composable
fun MainNavGraph(navController: NavHostController) {
    NavHost(navController = navController, startDestination = "home") {
        composable("home") { HomeScreen(navController) }
        composable("profile") { ProfileScreen(navController) }
        composable("nested_container") { NestedContainerScreen(navController) }
    }
}

@Composable
fun NestedContainerScreen(navController: NavHostController) {
    // Create a nested NavController for the subgraph
    val nestedNavController = rememberNavController()

    // Nested NavHost as the subgraph
    NavHost(navController = nestedNavController, startDestination = "nested_home") {
        composable("nested_home") {
            NestedHomeScreen(nestedNavController)
        }
        composable("nested_detail/{id}") { backStackEntry ->
            val id = backStackEntry.arguments?.getString("id")
            NestedDetailScreen(id = id)
        }
    }
}

val nestedHomeViewModel : HomeViewModel = hiltViewModel()

//need to access it in parent nav host home screen

Note:

  1. Do not use global scope viewmodel to parent navhost to share
  2. Do not use subgraph using navigation
Share Improve this question asked Nov 18, 2024 at 13:09 Santhosh KumarSanthosh Kumar 5631 silver badge11 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

NavBackStackEntry is also a ViewModelStoreOwner that stores ViewModels and return same ViewModels for same ViewModel classes by using them as String keys. ViewModels are stored in ViewModelStore with

private val map = mutableMapOf<String, ViewModel>()

If you scope your ViewModel with a parent NavBackStackEntry you can access it from multiple graphs or navigations.

val parentBackStackEntry: NavBackStackEntry = navController.getBackStackEntry("home")

val nestedHomeViewModel : HomeViewModel = hiltViewModel(parentBackStackEntry)

As you can see hiltViewModel takes a LocalViewModelStoreOwner which is from current destination via LocalViewModelStoreOwner.current

@Composable
inline fun <reified VM : ViewModel> hiltViewModel(
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    },
    key: String? = null
): VM {
    val factory = createHiltViewModelFactory(viewModelStoreOwner)
    return viewModel(viewModelStoreOwner, key, factory = factory)
}

Also be advised that getBackStackEntry is not found it throws exception because of that you might use try-catch, store a constant or use type-safe navigation to make sure that you access parent NavBackStackEntry.

I'm working with Jetpack Compose and Hilt for dependency injection in a nested navigation setup. I need to share a ViewModel (specifically, nested_home ViewModel) between a nested screen (NestedHomeScreen) and its parent screen (HomeScreen). Both screens are part of different navigation graphs, but I want the HomeScreen to be able to access the same ViewModel instance used in NestedHomeScreen.

@Composable
fun MainNavGraph(navController: NavHostController) {
    NavHost(navController = navController, startDestination = "home") {
        composable("home") { HomeScreen(navController) }
        composable("profile") { ProfileScreen(navController) }
        composable("nested_container") { NestedContainerScreen(navController) }
    }
}

@Composable
fun NestedContainerScreen(navController: NavHostController) {
    // Create a nested NavController for the subgraph
    val nestedNavController = rememberNavController()

    // Nested NavHost as the subgraph
    NavHost(navController = nestedNavController, startDestination = "nested_home") {
        composable("nested_home") {
            NestedHomeScreen(nestedNavController)
        }
        composable("nested_detail/{id}") { backStackEntry ->
            val id = backStackEntry.arguments?.getString("id")
            NestedDetailScreen(id = id)
        }
    }
}

val nestedHomeViewModel : HomeViewModel = hiltViewModel()

//need to access it in parent nav host home screen

Note:

  1. Do not use global scope viewmodel to parent navhost to share
  2. Do not use subgraph using navigation

I'm working with Jetpack Compose and Hilt for dependency injection in a nested navigation setup. I need to share a ViewModel (specifically, nested_home ViewModel) between a nested screen (NestedHomeScreen) and its parent screen (HomeScreen). Both screens are part of different navigation graphs, but I want the HomeScreen to be able to access the same ViewModel instance used in NestedHomeScreen.

@Composable
fun MainNavGraph(navController: NavHostController) {
    NavHost(navController = navController, startDestination = "home") {
        composable("home") { HomeScreen(navController) }
        composable("profile") { ProfileScreen(navController) }
        composable("nested_container") { NestedContainerScreen(navController) }
    }
}

@Composable
fun NestedContainerScreen(navController: NavHostController) {
    // Create a nested NavController for the subgraph
    val nestedNavController = rememberNavController()

    // Nested NavHost as the subgraph
    NavHost(navController = nestedNavController, startDestination = "nested_home") {
        composable("nested_home") {
            NestedHomeScreen(nestedNavController)
        }
        composable("nested_detail/{id}") { backStackEntry ->
            val id = backStackEntry.arguments?.getString("id")
            NestedDetailScreen(id = id)
        }
    }
}

val nestedHomeViewModel : HomeViewModel = hiltViewModel()

//need to access it in parent nav host home screen

Note:

  1. Do not use global scope viewmodel to parent navhost to share
  2. Do not use subgraph using navigation
Share Improve this question asked Nov 18, 2024 at 13:09 Santhosh KumarSanthosh Kumar 5631 silver badge11 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

NavBackStackEntry is also a ViewModelStoreOwner that stores ViewModels and return same ViewModels for same ViewModel classes by using them as String keys. ViewModels are stored in ViewModelStore with

private val map = mutableMapOf<String, ViewModel>()

If you scope your ViewModel with a parent NavBackStackEntry you can access it from multiple graphs or navigations.

val parentBackStackEntry: NavBackStackEntry = navController.getBackStackEntry("home")

val nestedHomeViewModel : HomeViewModel = hiltViewModel(parentBackStackEntry)

As you can see hiltViewModel takes a LocalViewModelStoreOwner which is from current destination via LocalViewModelStoreOwner.current

@Composable
inline fun <reified VM : ViewModel> hiltViewModel(
    viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
    },
    key: String? = null
): VM {
    val factory = createHiltViewModelFactory(viewModelStoreOwner)
    return viewModel(viewModelStoreOwner, key, factory = factory)
}

Also be advised that getBackStackEntry is not found it throws exception because of that you might use try-catch, store a constant or use type-safe navigation to make sure that you access parent NavBackStackEntry.

本文标签: kotlinHow to share nested nav graph screen viewmodel to parent nav graph screenStack Overflow