Implement navigation with the Navigation Architecture Component

The Navigation Architecture Component simplifies the implementation of navigation between destinations in your app. A set of destinations compose an app’s navigation graph.

A destination is any place you can navigate to in your app. While destinations are usually Fragments representing specific screens, the Navigation Architecture Component supports other destination types:

  • Activities
  • Navigation graphs and subgraphs - when the destination is a graph or subgraph, you navigate to the starting destination of that graph or subgraph
  • Custom destination types

In addition to destinations, a navigation graph has connections between destinations called actions. Figure 1 shows a visual representation of a navigation graph for a sample app containing 6 destinations connected by 5 actions.

Figure 1. A navigation graph

The Navigation Architecture Component is implemented based on the Principles of navigation.

Set up the Navigation Architecture Component for your project

Before you can create a navigation graph, you must set up the Navigation Architecture Component for your project. To set up your project in Android Studio, do the following.

  1. If using a Beta, Release Candidate, or Stable build, you must enable the Navigation Editor. Click File > Settings (Android Studio > Preferences on Mac), select the Experimental category in the left pane, check Enable Navigation Editor, and then restart Android Studio.

  2. Add the following Navigation Architecture Component to your app or module's build.gradle file. For more information on adding Archtecture Components to build.gradle, refer to Adding components to your project.

Create a navigation graph

To add a navigation graph to your project, do the following:

  1. In the Project window, right-click on the res directory and select New > Android Resource File. The New Resource File dialog appears.

  2. Type a name in the File name field, such as "nav_graph".

  3. Select Navigation from the Resource type drop-down list.

  4. Click OK. The following occurs:

    1. A navigation resource directory is created within the res directory.
    2. A nav_graph.xml file is created within the navigation directory.
    3. The nav_graph.xml file opens in the Navigation Editor. This xml file contains your navigation graph.
  5. Click the Text tab to toggle to the XML text view. The XML for an empty navigation graph looks like this:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:android="http://schemas.android.com/apk/res/android">
    </navigation>
    
  6. Click Design to return to the Navigation Editor.

Tour the Navigation Editor

In the Navigation Editor, you can quickly build navigation graphs instead of building the graph's XML by hand. As shown in figure 2, the Navigation Editor has three sections:

Figure 2. The Navigation Editor

The Navigation Editor's sections are:

  1. The Destinations list - Lists all destinations currently in the Graph Editor.
  2. The Graph Editor - Contains a visual representation of your navigation graph.
  3. The Attributes Editor - Contains attributes associated with destinations and actions in your navigation graph.

Identify destinations

The first step in creating a navigation graph is to identify the destinations for your app. You can create blank destinations or create destinations from fragments and Activities in an existing project.

To identify destinations for your app, use the following steps.

  1. From the Graph Editor, click New Destination . The New Destination dialog appears.

  2. Click Create blank destination or click on a fragment or activity. The New Android Component dialog appears.

  3. Enter a name in the Fragment Name field. This name is the name of the fragment's class.

  4. Enter a name in the Fragment Layout Name field. This name is the name of the layout file for the fragment.

  5. Click Finish. A box representing the destination appears in the Graph Editor and in the list of Destinations. The following occurs:

    • If you created a blank destination, the Graph Editor displays the message “Hello blank fragment” in the destination. If you clicked on a fragment or activity, the Graph Editor displays a preview of the layout for that activity or fragment.

    • A Fragment subclass is created for your project. This class has the name you assigned in step 3.

    • A resource file is created for your project. This file has the name you assigned in step 4.

    Figure 3 shows a blank and an existing destination.

    Figure 3. New and existing destinations in the Graph Editor
  6. Click on the newly inserted destination to highlight the destination. The following attributes appear in the Attributes panel:

    • The Type field contains “Fragment” or “Activity” to indicate whether the destination is implemented as a fragment or activity in your source code.

    • The Label field contains the name of the destination’s XML layout file.

    • The ID field contains ID of the destination which will be used to refer to the destination in code.

    • The Class field contains the name of the class for the destination.

  7. Click the Text tab to toggle to the XML view. The XML now contains id, name (class name), label, and layout attributes based on names for the existing class and layout files:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:android="http://schemas.android.com/apk/res/android"
        app:startDestination="@id/blankFragment">
        <fragment
            android:id="@+id/blankFragment"
            android:name="com.example.cashdog.cashdog.BlankFragment"
            android:label="Blank"
            tools:layout="@layout/fragment_blank" />
    </navigation>
    

Connect destinations

You must have more than one destination to connect destinations. Following is the XML for a navigation graph with two blank destinations:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination="@id/blankFragment">
    <fragment
        android:id="@+id/blankFragment"
        android:name="com.example.cashdog.cashdog.BlankFragment"
        android:label="fragment_blank"
        tools:layout="@layout/fragment_blank" />
    <fragment
        android:id="@+id/blankFragment2"
        android:name="com.example.cashdog.cashdog.BlankFragment2"
        android:label="Blank2"
        tools:layout="@layout/fragment_blank_fragment2" />
</navigation>

Destinations are connected using actions. To connect two destinations:

  1. From the Graph Editor, hover over the right side of the destination that you want users to navigate from. A circle appears on the destination.

    Figure 4. Action connection circle
  2. Click and hold, drag your cursor over the destination you want users to navigate to, and release. A line is drawn to indicate navigation between the two destinations.

    Figure 5. Connected destinations
  3. Click on the arrow to highlight the action. The following attributes appear in the Attributes panel:

    • The Type field contains “Action.”
    • The ID field contains a system-assigned ID for the action.
    • The Destination field contains the ID for destination fragment or activity.
  4. Click the Text tab to toggle to the XML view. An action element has been added to the parent destination. The action has a system-assigned ID and destination attribute containing the ID of the next destination. For example:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:android="http://schemas.android.com/apk/res/android"
        app:startDestination="@id/blankFragment">
        <fragment
            android:id="@+id/blankFragment"
            android:name="com.example.cashdog.cashdog.BlankFragment"
            android:label="fragment_blank"
            tools:layout="@layout/fragment_blank" >
            <action
                android:id="@+id/action_blankFragment_to_blankFragment2"
                app:destination="@id/blankFragment2" />
        </fragment>
        <fragment
            android:id="@+id/blankFragment2"
            android:name="com.example.cashdog.cashdog.BlankFragment2"
            android:label="fragment_blank_fragment2"
            tools:layout="@layout/fragment_blank_fragment2" />
    </navigation>
    

Designate a screen as the start destination

The Graph Editor places an icon of a house next to the name of the first destination in your app. This icon indicates that this is the starting destination in the Navigation Graph. You can designate another destination as a starting destination using the following steps:

  1. From the Graph Editor, click on the destination. The destination is highlighted.
  2. Click Set Start Destination in the Attributes panel. The destination is now the start destination.

Modify an activity to host navigation

An activity hosts navigation for an app through the implementation of a NavHost interface which is added to your activity’s layout. The NavHost is an empty container where destinations are swapped in and out as a user navigates through your app.

The Navigation Architecture Component’s default NavHost implementation is NavHostFragment.

Add a NavHostFragment using the Layout Editor

You can use the Layout Editor to add a NavHostFragment to an activity by following these steps:

  1. Create a navigation graph resource if you don't already have one.

  2. In your list of project files, double-click on your activity's layout XML file to open it in the Layout Editor.

  3. Within the Palette pane, choose the Containers category, or alternatively search for "NavHostFragment".

  4. Drag the NavHostFragment view onto your activity.

  5. Next, in the Navigation Graphs dialog that appears, choose the corresponding navigation graph to associate with this NavHostFragment, and then click OK.

Back in Text view, notice that Android Studio has added XML similar to the following:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        app:defaultNavHost="true"
        app:navGraph="@navigation/mobile_navigation" />

</android.support.constraint.ConstraintLayout>

The app:defaultNavHost="true" attribute ensures that your NavHostFragment intercepts the system Back button. You can also implement this behavior by overwriting AppCompatActivity.onSupportNavigateUp() and calling NavController.navigateUp, as shown in the example below:

Kotlin

override fun onSupportNavigateUp()
        = findNavController(R.id.nav_host_fragment).navigateUp()

Java

@Override
public boolean onSupportNavigateUp() {
    return Navigation.findNavController(this, R.id.nav_host_fragment).navigateUp();
}

Create the NavHostFragment programmatically

You can also 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) // this is the 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) // this is the equivalent to app:defaultNavHost="true"
    .commit();

Tie destinations to UI widgets

Navigating to a destination is done using the NavController class. A NavController can be retrieved using one of the following static methods:

After you retrieve a NavController, use its navigate() method to navigate to a destination. The navigate() method accepts a resource ID. The ID can be the ID of a specific destination in the navigation graph or of an action. Using the ID of the action, instead of the resource ID of the destination, has advantages, such as associating transitions with your navigation. For more on transitions, refer to Create a transition between destinations.

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);
    }
});

The Android system maintains a back stack containing the last visited destination. 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 the top of the stack. Conversely, pressing the Up or Back button calls the NavController.navigateUp() and NavController.popBackStack() methods, respectively, to pop the top destination off of the stack.

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

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.

Group destinations into a nested navigation graph

A series of destinations can be grouped into a sub-graph within a navigation graph. The sub-graph is called a nested graph while the containing graph is called the “root graph.” Nested graphs are useful to organize and reuse sections of your app’s UI, such as a separate login flow.

As with a root graph, a nested graph must have a destination identified as the starting destination. The nested graph encapsulates its destinations; destinations outside of the nested graph, such as those on the root graph, only accesses the nested graph through its starting destination. Figure 6 shows a navigation graph for a simple money transfer app. This graph has two flows: A flow allowing the user to send money and a flow allowing the user to view their balance.

Figure 6. Money transfer navigation graph

To group destinations into a nested graph:

  1. From the Graph Editor, press and hold shift and click on the destinations you want include in the nested graph. Each destination is highlighted.

  2. Open the context menu and select Move to Nested Graph > New Graph. The destinations are enclosed in a nested graph. Figure 7 shows a nested graph in the Graph Editor.

    Figure 4. Nested graph in the Graph Editor
  3. Click on the nested graph to highlight it. The following attributes appear in the Attributes panel:

    • The Type field contains “Nested Graph.”
    • The ID field contains a system-assigned ID for the nested graph. This ID is used to reference the nested graph within your code.
  4. Double-click on the nested graph. The destinations in the nested graph appear.

  5. In the list of Destinations, click Root to return to the root navigation graph.

  6. Click the Text tab to toggle to the XML view. A nested navigation graph has been added to the graph. This navigation graph has its own open and close navigation elements. This nested graph has an ID of sendMoneyGraph and a startDestination attribute pointing to the first destination (chooseRecipient) in the nested graph:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools"
       xmlns:android="http://schemas.android.com/apk/res/android"
       app:startDestination="@id/mainFragment">
       <fragment
           android:id="@+id/mainFragment"
           android:name="com.example.cashdog.cashdog.MainFragment"
           android:label="fragment_main"
           tools:layout="@layout/fragment_main" >
           <action
               android:id="@+id/action_mainFragment_to_chooseRecipient"
               app:destination="@id/sendMoneyGraph" />
           <action
               android:id="@+id/action_mainFragment_to_viewBalanceFragment"
               app:destination="@id/viewBalanceFragment" />
       </fragment>
       <fragment
           android:id="@+id/viewBalanceFragment"
           android:name="com.example.cashdog.cashdog.ViewBalanceFragment"
           android:label="fragment_view_balance"
           tools:layout="@layout/fragment_view_balance" />
       <navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient">
           <fragment
               android:id="@+id/chooseRecipient"
               android:name="com.example.cashdog.cashdog.ChooseRecipient"
               android:label="fragment_choose_recipient"
               tools:layout="@layout/fragment_choose_recipient">
               <action
                   android:id="@+id/action_chooseRecipient_to_chooseAmountFragment"
                   app:destination="@id/chooseAmountFragment" />
           </fragment>
           <fragment
               android:id="@+id/chooseAmountFragment"
               android:name="com.example.cashdog.cashdog.ChooseAmountFragment"
               android:label="fragment_choose_amount"
               tools:layout="@layout/fragment_choose_amount" />
       </navigation>
    </navigation>
    
  7. In your code, pass the resource ID of the action connecting the root graph to the nested graph:

    Kotlin

    view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)
    

    Java

    Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
    

Reference other navigation graphs with <include>

Within a navigation graph, you can reference other graphs by using &lt;include&gt;. While this is functionally the same as using a nested graph, &lt;include&gt; lets you use graphs from other project modules or from library projects, as shown in the example below:

<include app:graph="@navigation/included_graph"/>

<include> contains a single attribute, app:graph, that points to the graph resource to be included. No other attributes are allowed.

In Android, a deep link is a URI that points to a specific destination in an app. These URIs are useful when you want to send users to a specific destination to perform some task in your app, such as a send money flow allowing the user to quickly send money to someone.

To assign a deep link to a destination in your navigation graph:

  1. From the Graph Editor, select the destination for the deep link.

  2. Click + in the Deep Links section of the Attributes panel. An Add Deep Link dialog box appears.

  3. Type a URI into the URI field, such as "www.cashdog.com/sendmoney" which represents the starting destination of a send money nested graph in an app.

    Note the following:

    • URIs without a scheme are assumed as http and https. For example, www.cashdog.com matches http://www.cashdog.com and https://www.cashdog.com.

    • Placeholders in the form of {placeholder_name} matches 1 or more characters. The String value of the placeholder is available in the arguments Bundle with a key of the same name. For example, http://www.example.com/users/{id} matches http://www.example.com/users/4.

    • The .* wildcard can be used to match 0 or more characters.

  4. (optional) Check Auto Verify to require Google to verify that you are the owner of the URI. For more information, refer to Verify Android App Links.

  5. Click Add. A link icon appears above the selected destination to indicate that destination has a deep link.

  6. Click the Text tab to toggle to the XML view. A nested deep link element has been added to the destination:

<deepLink app:uri="https://cashdog.com/sendmoney"/>

When a user uses the Back button from a deep link destination, they navigate back up the navigation stack just as though they entered your app from the app’s entry point.

Add an intent filter for a deep link

You must make additions to your manifest.xml file to enable deep linking in your app:

  • For Android Studio 3.0 and 3.1, you must manually add an intent-filter element. For more information, refer to Create Deep Links to App Content.

  • For Android Studio 3.2+, you can add a nav-graph element to your activity elements:

<activity name=".MainActivity">
    <nav-graph android:value="@navigation/main_nav" />
</activity>

As part of the manifest merging build step, this element is replaced with the generated <intent-filter> elements needed to match all of the deep links in the navigation graph.

You can use the NavDeepLinkBuilder class to construct a PendingIntent that takes the user to a specific destination.

When this deep link is triggered, the task back stack is cleared and replaced with the deep link destination. When nesting graphs, the start destination from each level of nesting—that is, the start destination from each <navigation> element in the hierarchy—is also added to the stack.

You can construct a PendingIntent directly with NavDeepLinkBuilder(Context), as shown in the example below. Note that if the provided context is not an Activity, the constructor uses PackageManager.getLaunchIntentForPackage() as the default activity to launch, if available.

Kotlin

val pendingIntent = NavDeepLinkBuilder(context)
    .setGraph(R.navigation.mobile_navigation)
    .setDestination(R.id.android)
    .setArguments(args)
    .createPendingIntent()

Java

PendingIntent pendingIntent = new NavDeepLinkBuilder(context)
    .setGraph(R.navigation.mobile_navigation)
    .setDestination(R.id.android)
    .setArguments(args)
    .createPendingIntent();

For a complete navigation project that includes this example, see the Navigation Codelab.

Create a transition between destinations

The Navigation Architecture Component provides functionality to easily add transitions, such as fade-in and fade-out, between destinations. To add a transition:

  1. Create your animation resource files. The Navigation Architecture Component supports property and view animations. For further information, refer to Animation resources.

  2. From the Graph Editor, click on an action where the transition should occur.

  3. In the Transitions section of the Attributes panel, click the down arrow next to Enter. A list of transitions in your project appears.

  4. Select the transition to occur when a user enters the destination.

  5. In the Transitions section of the Attributes panel, click the down arrow next to Exit. A list of transitions in your project appears.

  6. Select the transition to occur when a user exits the destination.

  7. Click the Text tab to toggle to the XML text view. The XML for the transition appears in the action element for the action specified in step 2. The action is embedded within the XML for the destination that is active before the transition occurs. In the following example, specifyAmountFragment is the active destination and it contains the action with the transition animations:

    <fragment
        android:id="@+id/specifyAmountFragment"
        android:name="com.example.buybuddy.buybuddy.SpecifyAmountFragment"
        android:label="fragment_specify_amount"
        tools:layout="@layout/fragment_specify_amount">
        <action
            android:id="@+id/confirmationAction"
            app:destination="@id/confirmationFragment"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right" />
     </fragment>
    

    In this example we have transitions that take place when moving to a destination (enterAnim and exitAnim and when exiting that destination (popEnterAnim and popExitAnim).

Add Shared Element Transitions between destinations

In addition to transition animations, the Navigation Architecture Component supports adding shared element transitions between destinations.

Shared element transitions, unlike animations, are supplied programmatically rather than through your navigation XML file, as they require referencing the View instances that you wish to include in the shared element transition.

Each type of destination implements this programmatic API through a subclass of the Navigator.Extras interface. The Extras are passed to a call to navigate().

Fragment Destination Shared Element Transitions

The FragmentNavigator.Extras class allows you to attach shared elements to navigate() calls to Fragment destinations, as shown in the example below:

Kotlin

val extras = FragmentNavigatorExtras(
    imageView to "header_image",
    titleView to "header_title")
view.findNavController().navigate(R.id.confirmationAction,
    null, // Bundle of args
    null, // NavOptions
    extras)

Java

FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
    .addSharedElement(imageView, "header_image")
    .addSharedElement(titleView, "header_title")
    .build();
Navigation.findNavController(view).navigate(R.id.details,
    null, // Bundle of args
    null, // NavOptions
    extras);

Activity Destination Shared Element Transitions

Activities rely on ActivityOptionsCompat to control Shared Element Transitions as detailed in the Start an activity with a shared element documentation and as shown in the example below:

Kotlin

// Rename the Pair class from the Android framework to avoid a name clash
import android.util.Pair as UtilPair
...
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
        UtilPair.create(imageView, "header_image"),
        UtilPair.create(titleView, "header_title"))
val extras = ActivityNavigator.Extras(options)
view.findNavController().navigate(R.id.details,
    null, // Bundle of args
    null, // NavOptions
    extras)

Java

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
        Pair.create(imageView, "header_image"),
        Pair.create(titleView, "header_title"));

ActivityNavigator.Extras extras = new ActivityNavigator.Extras.Builder()
    .setActivityOptions(options)
    .build();
Navigation.findNavController(view).navigate(R.id.details,
    null, // Bundle of args
    null, // NavOptions
    extras);

Report an issue

If you encounter any issues with the Navigation Editor, please submit a report in Issue Tracker. For information on how to provide the most helpful information in issue reports, see Report a bug.

What's next

This document explained the fundamentals to implement navigation. The following additional navigation topics are available: