Interact programmatically with the Navigation component

The Navigation component provides ways to programmatically create and interact with certain navigation elements.

Create a NavHostFragment

You can use NavHostFragment.create() to programmatically create a NavHostFragment with a specific graph resource, as shown in the example below:

Kotlin

val finalHost = NavHostFragment.create(R.navigation.example_graph)
supportFragmentManager.beginTransaction()
    .replace(R.id.nav_host, finalHost)
    .setPrimaryNavigationFragment(finalHost) // equivalent to app:defaultNavHost="true"
    .commit()

Java

NavHostFragment finalHost = NavHostFragment.create(R.navigation.example_graph);
getSupportFragmentManager().beginTransaction()
    .replace(R.id.nav_host, finalHost)
    .setPrimaryNavigationFragment(finalHost) // equivalent to app:defaultNavHost="true"
    .commit();

Note that setPrimaryNavigationFragment(finalHost) lets your NavHost intercept system Back button presses. You can also implement this behavior in your NavHost XML by adding app:defaultNavHost="true". If you're implementing custom Back button behavior and don't want your NavHost intercepting Back button presses, you can pass null to setPrimaryNavigationFragment().

Starting with Navigation 2.2.0, you can get a reference to the NavBackStackEntry for any destination on the navigation stack by calling NavController.getBackStackEntry(), passing it a destination ID. If the back stack contains more than one instance of the specified destination, getBackStackEntry() returns the topmost instance from the stack.

The returned NavBackStackEntry provides a Lifecycle, a ViewModelStore, and a SavedStateRegistry at the destination level. These objects are valid for the lifetime of the destination on the back stack. When the associated destination is popped off the back stack, the Lifecycle is destroyed, the state is no longer saved, and any ViewModel objects are cleared.

These properties give you a Lifecycle and a store for ViewModel objects and classes that work with saved state no matter what type of destination you use. This is especially useful when working with destination types which do not automatically have an associated Lifecycle, such as custom destinations.

For example, you can observe the Lifecycle of a NavBackStackEntry just as you would observe the Lifecycle of a fragment or activity. In addition, NavBackStackEntry is a LifecycleOwner, which means that you can use it when observing LiveData or with other lifecycle-aware components, as shown in the following example:

Kotlin

myViewModel.liveData.observe(backStackEntry, Observer { myData ->
    // react to live data update
})

Java

myViewModel.getLiveData().observe(backStackEntry, myData -> {
    // react to live data update
});

Lifecycle state automatically updates whenever you call navigate(). Lifecycle states for destinations that are not at the top of the back stack move from RESUMED to STARTED if the destinations are still visible under a FloatingWindow destination, such as a dialog destination, or to STOPPED otherwise.

The Navigation back stack stores a NavBackStackEntry not only for each individual destination, but also for each parent navigation graph that contains the individual destination. This allows you to retrieve a NavBackStackEntry that is scoped to a navigation graph. A navigation graph-scoped NavBackStackEntry provides a way to create a ViewModel that's scoped to a navigation graph, enabling you to share UI-related data between the graph's destinations. Any ViewModel objects created in this way live until the associated NavHost and its ViewModelStore are cleared or until the navigation graph is popped from the back stack.

The following example shows how to retrieve a ViewModel that's scoped to a navigation graph:

Kotlin

val viewModel: MyViewModel
        by navGraphViewModels(R.id.my_graph)

Java

NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);
MyViewModel viewModel = new ViewModelProvider(backStackEntry).get(MyViewModel.class);

If you're using Navigation 2.2.0 or earlier, you need to provide your own factory to use Saved State with ViewModels, as shown in the following example:

Kotlin

val viewModel: MyViewModel by navGraphViewModels(R.id.my_graph) {
    SavedStateViewModelFactory(requireActivity().application, requireParentFragment())
}

Java

NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

ViewModelProvider viewModelProvider = new ViewModelProvider(
        backStackEntry.getViewModelStore(),
        new SavedStateViewModelFactory(
                requireActivity().getApplication(), requireParentFragment()));

MyViewModel myViewModel = provider.get(myViewModel.getClass());

For more information about ViewModel, see ViewModel Overview.