Navigate to a destination

Navigating to a destination is done using a NavController, an object that manages app navigation within a NavHost. Each NavHost has its own corresponding NavController. NavController provides a few different ways to navigate to a destination, which are further described in the sections below.

To retrieve the NavController for a fragment, activity, or view, use one of the following methods:

Kotlin:

Java:

Navigate using ID

navigate(int) takes the resource ID of either an action or a destination. The following code snippet shows how to navigate to the ViewTransactionsFragment:

Kotlin

viewTransactionsButton.setOnClickListener { view ->
   view.findNavController().navigate(R.id.viewTransactionsAction)
}

Java

viewTransactionsButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Navigation.findNavController(view).navigate(R.id.viewTransactionsAction);
    }
});

For buttons, you can also use the Navigation class’s createNavigateOnClickListener() convenience method to navigate to a destination, as shown in the following example:

Kotlin

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null))

Java

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));

To handle other common UI components, such as the top app bar and bottom navigation, see Update UI components with NavigationUI.

When you define an action in the navigation graph, Navigation generates a corresponding NavAction class, which contains the configurations defined for that action, including the following:

  • Destination: The resource ID of the target destination.
  • Default arguments: An android.os.Bundle containing default values for the target destination, if supplied.
  • Navigation options: Navigation options, represented as NavOptions. This class contains all of the special configuration for transitioning to and back from the target destination, including animation resource configuration, pop behavior, and whether the destination should be launched in single top mode.

Let’s take a look at an example graph consisting of two screens along with an action to navigate from one to the other:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/nav_graph"
            app:startDestination="@id/a">

    <fragment android:id="@+id/a"
              android:name="com.example.myapplication.FragmentA"
              android:label="a"
              tools:layout="@layout/a">
        <action android:id="@+id/action_a_to_b"
                app:destination="@id/b"
                app:enterAnim="@anim/nav_default_enter_anim"
                app:exitAnim="@anim/nav_default_exit_anim"
                app:popEnterAnim="@anim/nav_default_pop_enter_anim"
                app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
    </fragment>

    <fragment android:id="@+id/b"
              android:name="com.example.myapplication.FragmentB"
              android:label="b"
              tools:layout="@layout/b">
        <action android:id="@+id/action_b_to_a"
                app:destination="@id/a"
                app:enterAnim="@anim/nav_default_enter_anim"
                app:exitAnim="@anim/nav_default_exit_anim"
                app:popEnterAnim="@anim/nav_default_pop_enter_anim"
                app:popExitAnim="@anim/nav_default_pop_exit_anim"
                app:popUpTo="@+id/a"
                app:popUpToInclusive="true"/>
    </fragment>
</navigation>

When the navigation graph is inflated, these actions are parsed, and corresponding NavAction objects are generated with the configurations defined in the graph. For example, action_b_to_a is defined as navigating from destination b to destination a. The action includes animations along with popTo behavior that removes all destinations from the backstack. All of these settings are captured as NavOptions and are attached to the NavAction.

To follow this NavAction, use NavController.navigate(), passing the ID of the action, as shown in the following example:

Kotlin

findNavController().navigate(R.id.action_b_to_a)

Java

Navigation.findNavController(this).navigate(R.id.action_b_to_a);

Navigate using URI

You can use navigate(Uri) to navigate directly to an implicit deep link destination, as shown in the following example:

Kotlin

val navController = findNavController()
val deeplink = Uri.parse("android-app://androidx.navigation.app/profile")
findNavController().navigate(deeplink)

Java

Uri deeplink = Uri.parse("android-app://androidx.navigation.app/profile");
view.findNavController().navigate(deeplink);

Unlike navigation using action or destination IDs, you can navigate to any URI in your graph, regardless of whether the destination is visible. You can navigate to a destination on the current graph or a destination on a completely different graph.

When navigating using URI, the back stack is not reset. This is unlike other deep link navigation, where the back stack is replaced when navigating. popUpTo and popUpToInclusive, however, still remove destinations from the back stack just as though you had navigated using an ID.

Navigation and the back stack

Android maintains a back stack that contains the destinations you've visited. The first destination of your app is placed on the stack when the user opens the app. Each call to the navigate() method puts another destination on top of the stack. Tapping Up or Back calls the NavController.navigateUp() and NavController.popBackStack() methods, respectively, to remove (or pop) the top destination off of the stack.

popUpTo and popUpToInclusive

When navigating using an action, you can optionally pop additional destinations off of the back stack. For example, if your app has an initial login flow, once a user has logged in, you should pop all of the login-related destinations off of the back stack so that the Back button doesn't take users back into the login flow.

To pop destinations when navigating from one destination to another, add an app:popUpTo attribute to the associated <action> element. app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate(). The attribute value is the ID of the most recent destination that should remain on the stack.

You can also include app:popUpToInclusive="true" to indicate that the destination specified in app:popUpTo should also be removed from the back stack.

popUpTo example: circular logic

Let's say that your app has three destinations—A, B, and C—along with actions that lead from A to B, B to C, and C back to A. The corresponding navigation graph is shown in figure 1:

Figure 1. A circular navigation graph with three destinations: A, B, and C.

With each navigation action, a destination is added to the back stack. If you were to navigate repeatedly through this flow, your back stack would then contain multiple sets of each destination (A, B, C, A, B, C, A, and so on). To avoid this repetition, you can specify app:popUpTo and app:popUpToInclusive in the action that takes you from destination C to destination A, as shown in the following example:

<fragment
    android:id="@+id/c"
    android:name="com.example.myapplication.C"
    android:label="fragment_c"
    tools:layout="@layout/fragment_c">

    <action
        android:id="@+id/action_c_to_a"
        app:destination="@id/a"
        app:popUpTo="@+id/a"
        app:popUpToInclusive="true"/>
</fragment>

After reaching destination C, the back stack contains one instance of each destination (A, B, C). When navigating back to destination A, we also popUpTo A, which means that we remove B and C from the stack while navigating. With app:popUpToInclusive="true", we also pop that first A off of the stack, effectively clearing it. Notice here that if you don't use app:popUpToInclusive, your back stack would contain two instances of destination A.