Pass data between destinations

Navigation allows you to attach data to a navigation operation by defining arguments for a destination. For example, a user profile destination might take a user ID argument to determine which user to display.

In general, you should strongly prefer passing only the minimal amount of data between destinations. For example, you should pass a key to retrieve an object rather than passing the object itself, as the total space for all saved states is limited on Android. If you need to pass large amounts of data, consider using a ViewModel as described in Share data between fragments.

Define destination arguments

To pass data between destinations, first define the argument by adding it to the destination that receives it by following these steps:

  1. In the Navigation editor, click on the destination that receives the argument.
  2. In the Attributes panel, click Add (+).
  3. In the Add Argument Link window that appears, enter the argument name, argument type, whether the argument is nullable, and a default value, if needed.
  4. Click Add. Notice that the argument now appears in the Arguments list in the Attributes panel.
  5. Next, click on the corresponding action that takes you to this destination. In the Attributes panel, you should now see your newly added argument in the Argument Default Values section.
  6. You can also see that the argument was added in XML. Click the Text tab to toggle to XML view, and notice that your argument was added to the destination that receives the argument. An example is shown below:

     <fragment android:id="@+id/myFragment" >
         <argument
             android:name="myArg"
             app:argType="integer"
             android:defaultValue="0" />
     </fragment>
    

Supported argument types

The Navigation library supports the following argument types:

Type app:argType syntax Supports default values? Supports null values?
Integer app:argType="integer" Yes No
Float app:argType="float" Yes No
Long app:argType="long" Yes - Default values must always end with an 'L' suffix (e.g. "123L"). No
Boolean app:argType="boolean" Yes - "true" or "false" No
String app:argType="string" Yes Yes
Resource Reference app:argType="reference" Yes - Default values must be in the form of "@resourceType/resourceName" (e.g. "@style/myCustomStyle") or "0" No
Custom Parcelable app:argType="<type>", where <type> is the fully-qualified class name of the Parcelable Supports a default value of "@null". Does not support other default values. Yes
Custom Serializable app:argType="<type>", where <type> is the fully-qualified class name of the Serializable Supports a default value of "@null". Does not support other default values. Yes
Custom Enum app:argType="<type>", where <type> is the fully-qualified name of the enum Yes - Default values must match the unqualified name (e.g. "SUCCESS" to match MyEnum.SUCCESS). No

When you choose one of the custom types, the Select Class dialog appears and prompts you to choose the corresponding class for that type. The Project tab lets you choose a class from your current project.

You can choose <inferred type> to have the Navigation library determine the type based on the provided value.

You can check Array to indicate that the argument should be an array of the selected Type value. Note that arrays of enums and arrays of resource references are not supported. Arrays are always nullable, regardless of the nullability of the underlying type. Arrays support a single default value, "@null". Arrays do not support any other default value.

Override a destination argument in an action

Destination-level arguments and default values are used by all actions that navigate to the destination. If needed, you can override the default value of an argument (or set one if it doesn't already exist) by defining an argument at the action level. This argument must be of the same name and type as the argument declared in the destination.

The XML below declares an action with an argument that overrides the destination-level argument from the example above:

<action android:id="@+id/startMyFragment"
    app:destination="@+id/myFragment">
    <argument
        android:name="myArg"
        app:argType="integer"
        android:defaultValue="1" />
</action>

Use Safe Args to pass data with type safety

The Navigation Architecture 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.

After enabling Safe Args, your generated code contains type-safe methods for each action along with the sending and receiving destinations. These classes are described below:

  • A class is created for each destination where an action originates. The name of this class is the name of the originating destination, appended with the word "Directions". For example, if the originating destination is a fragment that is named SpecifyAmountFragment, the generated class would be called SpecifyAmountFragmentDirections.

    This class has a method for each action defined in the originating destination.

  • For each action used to pass the argument, an inner class is created whose name is based on the action. For example, if the action is called confirmationAction, the class is named ConfirmationAction.

  • A class is created for the receiving destination. The name of this class is the name of the destination, appended with the word "Args". For example, if the destination fragment is named ConfirmationFragment, the generated class is called ConfirmationFragmentArgs. Use this class's fromBundle() method to retrieve the arguments.

The following example shows you how to use these methods to set an argument and pass it to the navigate() method:

Kotlin

override fun onClick(v: View) {
   val amountTv: EditText = view!!.findViewById(R.id.editTextAmount)
   val amount = amountTv.text.toString().toInt()
   val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
   v.findNavController().navigate(action)
}

Java

@Override
public void onClick(View view) {
   EditText amountTv = (EditText) getView().findViewById(R.id.editTextAmount);
   int amount = Integer.parseInt(amountTv.getText().toString());
   ConfirmationAction action =
           SpecifyAmountFragmentDirections.confirmationAction()
   action.setAmount(amount)
   Navigation.findNavController(view).navigate(action);
}

In your receiving destination’s code, use the getArguments() method to retrieve the bundle and use its contents. When using the -ktx dependencies, Kotlin users can also use the by navArgs() property delegate to access arguments.

Kotlin

val args: ConfirmationFragmentArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val tv: TextView = view.findViewById(R.id.textViewAmount)
    val amount = args.amount
    tv.text = amount.toString()
}

Java

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    TextView tv = view.findViewById(R.id.textViewAmount);
    int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount();
    tv.setText(amount + "")
}

Use Safe Args with a global action

When using Safe Args with a global action, you must provide an android:id value for your root <navigation> element, as shown in the following 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"
            android:id="@+id/main_nav"
            app:startDestination="@id/mainFragment">

    ...

</navigation>

Navigation generates a Directions class for the <navigation> element that is based on the android:id value. For example, if you have a <navigation> element with android:id=@+id/main_nav, the generated class is called MainNavDirections. All destinations within the <navigation> element have generated methods for accessing all associated global actions using the same methods as described in the previous section.

Pass data between destinations with Bundle objects

If you aren't using Gradle, you can still pass arguments between destinations by using Bundle objects. Create a Bundle object and pass it to the destination using navigate(), as shown below:

Kotlin

var bundle = bundleOf("amount" to amount)
view.findNavController().navigate(R.id.confirmationAction, bundle)

Java

Bundle bundle = new Bundle();
bundle.putString("amount", amount);
Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);

In your receiving destination’s code, use the getArguments() method to retrieve the Bundle and use its contents:

Kotlin

val tv = view.findViewById<TextView>(R.id.textViewAmount)
tv.text = arguments.getString("amount")

Java

TextView tv = view.findViewById(R.id.textViewAmount);
tv.setText(getArguments().getString("amount"));

Additional resources

To learn more about navigation, consult the following additional resources.

Samples

Codelabs

Videos