Move screen-specific UI logic out of activities - Move your app’s UI
logic out of activities, ensuring that each activity owns only the logic of
global navigation UI components, such as a Toolbar, while delegating the
implementation of each screen to a fragment or custom destination.

Integrate the Navigation component - For each activity, build a
navigation graph which contains the one or more fragments managed by that
activity. Replace fragment transactions with Navigation component operations.

Important: To ensure success, approach migration as an iterative process,
thoroughly testing your app with each step. While a single-activity architecture
allows you to take full advantage of the Navigation component, you do not need
to fully migrate your app to benefit from Navigation.

Prerequisites

This guide assumes that you have already migrated your app to use
AndroidX libraries. If you have not done so,
migrate your project to use AndroidX before
continuing.

Move screen-specific UI logic out of activities

Note: This section contains guidance on introducing fragments to an
activity-based app. If your app is already using fragments, you can skip ahead
to the Integrate the Navigation component section.

Activities are system-level components that facilitate a graphical interaction
between your app and Android. Activities are registered in your app’s manifest
so that Android knows which activities are available to launch. The activity
class enables your app to react to Android changes as well, such as when your
app’s UI is entering or leaving the foreground, rotating, and so on. The
activity can also serve as a place to
share state between screens.

Within the context of your app, activities should serve as a host for navigation
and should hold the logic and knowledge of how to transition between screens,
pass data, and so on. However, managing the details of your UI is better left
to a smaller, reusable part of your UI. The recommended implementation for this
pattern is fragments. See
Single Activity: Why, When, and How
to learn more about the advantages of using fragments. Navigation supports fragments via the navigation-fragment dependency. Navigation also supports
custom destination types.

If your app is not using fragments, the first thing you need to do is migrate
each screen in your app to use a fragment. You aren't removing the activity at
this point. Rather, you're creating a fragment to represent the screen and break
apart your UI logic by responsibility.

Introducing fragments

To illustrate the process of introducing fragments, let’s start with an example
of an application that consists of two screens: a product list screen and a
product details screen. Clicking on a product in the list screen takes the
user to a details screen to learn more about the product.

In this example, the list and details screens are currently separate activities.

Note: As you migrate to a fragment-based architecture, it’s important to focus
on one screen at a time. You may find it helpful to start from your app’s launch
screen and work your way through your app. This example focuses on migrating
only the list screen.

Create a New Layout to Host the UI

To introduce a fragment, start by creating a new layout file for the activity to
host the fragment. This replaces the activity’s current content view layout.

For a simple view, you can use a FrameLayout, as shown in the following
example product_list_host:

Kotlin

Java

Move activity logic into a fragment

With the fragment definition in place, the next step is to move the UI logic for
this screen from the activity into this new fragment. If you are coming from an
activity-based architecture, you likely have a lot of view creation logic
happening in your activity's onCreate() function.

Here's an example activity-based screen with UI logic that we need to move:

In ProductListFragment, notice that there is no call to
setContentView()
to inflate and connect the layout. In a fragment, onCreateView() initializes the
root view. onCreateView() takes an instance of a
LayoutInflater which can be used to
inflate the root view based on a layout resource file. This example reuses the
existing product_list layout which was used by the activity because nothing
needs to change to the layout itself.

If you have any UI logic residing in your activity’s onStart(), onResume(),
onPause() or onStop() functions that are not related to navigation, you can
move those to corresponding functions of the same name on the fragment.

Note: A fragment’s lifecycle is managed by its host activity and has additional
lifecycle callbacks other than the ones used in this example. Your app might
have a reason to override other lifecycle functions, as well. For a complete
list of fragment lifecycle functions and when to use them, see the
guide to fragments.

Initialize the fragment in the host activity

Once you have moved all of the UI logic down to the fragment, only navigation
logic should remain in the activity.

At this point, you should be able to test running your app with the first screen
updated to use a fragment. Continue to migrate the rest of your activity-based
screens, taking time to test after each iteration.

Integrate the Navigation component

Once you're using a fragment-based architecture, you are ready to start integrating the Navigation component.

Create a navigation graph

The Navigation component represents your app’s navigation configuration in a
resource file as a graph, much like your app’s views are represented. This helps
keep your app’s navigation organized outside of your codebase and provides a way
for you to edit your app navigation visually.

To create a navigation graph, start by creating a new resource folder called
navigation. To add the graph, right-click on this directory, and choose
New > Navigation resource file.

The Navigation component uses an activity as a
host for navigation
and swaps individual fragments into that host as your users navigate through
your app. Before you can start to layout out your app’s navigation visually, you
need to configure a NavHost inside of the activity that is going to host this
graph. Since we're using fragments, we can use the Navigation component's
default NavHost implementation,
NavHostFragment.

Note: If your app uses multiple activities, each activity uses a separate
navigation graph. To take full advantage of the Navigation component, your app
should use multiple fragments in a single activity. However, activities can
still benefit from the Navigation component. Note, however, that your app’s UI
must be visually broken up across several navigation graphs.

A NavHostFragment is configured via a <fragment> element placed inside of a
host activity, as shown in the following example:

The app:NavGraph attribute points to the navigation graph associated with this
navigation host. Setting this property inflates the nav graph and sets the graph
property on the NavHostFragment. The app:defaultNavHost attribute ensures
that your NavHostFragment intercepts the system Back button.

If you’re using top-level navigation such as a DrawerLayout or
BottomNavigationView, this <fragment> replaces your main content view
element. See
Update UI components with NavigationUI
for examples.

For a simple layout, you can include this <fragment> element as a child of the
root ViewGroup:

If you click on the Design tab at the bottom, you should see a graph similar
to the one shown below. In the upper left hand side of the graph, under
Destinations, you can see a reference to the NavHost activity in the form
of layout_name (resource_id).

Click the plus button
near the top to add your fragments to this graph.

The Navigation component refers to individual screens as destinations.
Destinations can be fragments, activities, or custom destinations. You can add
any type of destination to your graph, but note that activity destinations are
considered terminal destinations, because once you navigate to an activity
destination, you are operating within a separate navigation host and graph.

The Navigation component refers to the way in which users get from one
destination to another as actions. Actions can also describe transition
animations and pop behavior.

Remove fragment transactions

Now that you are using the Navigation component, if you are navigating between fragment-based screens under the same activity, you can remove
FragmentManager
interactions.

If your app is using multiple fragments under the same activity or top-level
navigation such as a drawer layout or bottom navigation, then you are probably
using a FragmentManager and
FragmentTransactions
to add or replace fragments in the main content section of your UI. This can now
be replaced and simplified using the Navigation component by providing actions
to link destinations within your graph and then navigating using the
NavController.

Here are a few scenarios you might encounter along with how you might approach
migration for each scenario.

Single activity managing multiple fragments

If you have a single activity that manages multiple fragments, your activity
code might look like this:

The activity no longer needs a navigateToProductDetail() method. In the next
section, we update ProductListFragment to use the NavController to navigate
to the next product detail screen.

Pass arguments safely

The Navigation component has a Gradle plugin called
Safe Args
that generates simple object and builder classes for type-safe access to
arguments specified for destinations and actions.

Once the plugin is applied, any arguments defined on a destination in your
navigation graph causes the Navigation component framework to generate an
Arguments class that provides type safe arguments to the target destination.
Defining an action causes the plugin to generate a Directions configuration
class which can be used to tell the NavController how to navigate the user to
the target destination. When an action points to a destination that requires
arguments, the generated Directions class includes constructor methods which
require those parameters.

Inside the fragment, use NavController and the generated Directions class to
provide type-safe arguments to the target destination, as shown in the following
example:

After you have added the Navigation component to your project and created a
navigation graph, add each of the content destinations from your graph (such as
Home, Gallery, SlideShow, and Tools from the example above). Be sure
that your menu item id values match their associated destination id values,
as shown below:

If you match the id values from your menu and graph, then you can wire up the
NavController for this activity to handle navigation automatically based on
the menu item. The NavController also handles opening and closing the
DrawerLayout and handling Up and Back button behavior appropriately.

Your MainActivity can then be updated to wire up the NavController to the
Toolbar and NavigationView.

Add activity destinations

Once each screen in your app is wired up to use the Navigation component, and
you are no longer using FragmentTransactions to transition between
fragment-based destinations, the next step is to eliminate startActivity
calls.

First, identify places in your app where you have two separate navigation graphs
and are using startActivity to transition between them.

This example contains two graphs (A and B) and a startActivity() call to
transition from A to B.

Java

Next, replace these with an activity destination in Graph A that represents the
navigation to the host activity of Graph B. If you have arguments to pass to the
start destination of Graph B, you can designate them in the activity destination
definition.

In the following example, Graph A defines an activity destination which takes a
product_id argument along with an action. Graph B contains no changes.

Pass activity destination args to a start destination fragment

If the destination activity receives extras, as with the previous example, you
can pass these to the start destination directly as arguments, but you need to
manually set your host’s navigation graph inside the host activity’s
onCreate() method so that you can pass the intent extras as arguments to the
fragment, as shown below:

Combine activities

You can combine navigation graphs in cases where multiple activities share the
same layout, such as a simple FrameLayout containing a single fragment. In
most of these cases, you can just combine all of the elements from each
navigation graph and updating any activity destination elements to fragment
destinations.

The following example combines Graphs A and B from the previous section:

Keeping your action names the same while merging can make this a seamless
process, requiring no changes to your existing code base. For example,
navigateToProductDetail remains the same here. The only difference is that
this action now represents navigation to a fragment destination within the same
NavHost instead of an activity destination: