Using Safe Args With the Android Navigation Component

In this Safe Args tutorial, you’ll learn how to safely pass data between different destinations while using the Android Navigation Component. By Husayn Hakeem.

5 (7) · 1 Review

Download materials
Save for later

Passing data between screens is a common use case in an Android app. This enables destinations to communicate with each other and builds a continuous flow inside an app. Google recommends using the Android Navigation Component to manage navigation between destinations in your app. In this tutorial, you’ll learn to use this component with Safe Args to pass data while navigating between screens.

You’ll build SafeFly, an app that lets you buy plane tickets. The first screen retrieves the user’s travel information, then passes it to a confirmation screen. During the process, you’ll learn:

  • Why you should use Safe Args.
  • How to pass data using Safe Args.
  • Things to consider when using Safe Args and code shrinking in the same app.
Note: This tutorial assumes you have previous experience using the Android Navigation Component. If you don’t, check out our Navigation Architecture Component tutorial.

Getting Started

Download the materials using the Download Materials button at the top or bottom of this tutorial. Open Android Studio and import the starter project.

Take a moment to familiarize yourself with the code. You’ll see the following classes:

  • TravelInformationFragment.kt: Fragment where the user enters their information.
  • ConfirmationFragment.kt: Fragment that displays the user’s travel information to confirm it.
  • TravelerInformation.kt: Data class that wraps personal user information required for purchasing a plane ticket.

Build and run the project. You’ll see a screen that allows the user to enter their information, which travel add-ons they want and a promo code, if they have one. On the next screen, you’ll notice the fields are all empty. The user’s information should display instead. That’s what you’ll handle next.

Starter project

Why Safe Args?

Before the introduction of Safe Args, passing data when navigating to a different screen required Bundles. The first screen, the sender, would build a Bundle instance and populate it with data. The second screen, the receiver, would later retrieve this data. This manual approach of sending and unwrapping data is unreliable, as the sender and receiver must agree on:

  • The keys.
  • The default values for each key.
  • The type of data corresponding to the keys.

There’s also no way for the receiver to force the sender to pass all the required data. Furthermore, when unwrapping the data, type safety isn’t guaranteed on the receiver’s end.

Android introduced Safe Args to resolve these issues. Safe Args is a Gradle plug-in that generates code to add data to a Bundle and get it back in a simple and type-safe manner.

Android passing data back and forth with arrows.

Now that you see why Safe Args is useful for your project, it’s time to implement it.

Note: Safe Args only works with Gradle, which means that you can’t use it if your projects use a different build tool.

Adding Safe Args to Your App

To add Safe Args to your project, include the following classpath in your top-level build.gradle:

dependencies {
  classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.2"

Apply Safe Args’s Kotlin plug-in by adding the following line to your app-level build.gradle at the top:

apply plugin: "androidx.navigation.safeargs.kotlin"

The plug-in above generates Kotlin code, so you should use it in Kotlin-only modules, such as in this tutorial.

If your module uses Java or a mix of Java and Kotlin, apply the following plug-in, which generates Java code:

apply plugin: "androidx.navigation.safeargs"

Click Sync now and wait for Gradle to sync the dependencies.

Passing Data With Safe Args

The data you pass from one destination to another is called an argument. This data can be a simple number or a complex model. Note that passing the minimal amount of data necessary between destinations is a best practice, because there’s a limit to the total space available for all saved states.

An argument can be of any type that Bundle supports, including:

  • Integer
  • Float
  • Long
  • Boolean
  • String
  • resource reference
  • Parcelable
  • Serializable
  • Enum

Primitive types — int, float, long and bool — back Integer, Float, Long and Boolean respectively on the JVM, so they can’t be null. In contrast, String, Parcelable and Serializable can accept null values.

You can provide a default value to an argument, which it will take if the sender doesn’t assign a value at runtime.

An argument can also be an array of any of the above types, except resource references and Enums. If an argument is an array, it can have a null value, regardless of its underlying type. Additionally, it can only have a null default value.

Defining an Argument in a Destination

The confirmation screen in the app expects to receive certain information: the traveler’s information, travel add-ons and promo code. The navigation graph should define these three arguments. In this section, you’ll see how to add arguments using the editor.

Open navigation_graph.xml, select the Design window at the top-right corner and click ConfirmationFragment.

Adding Safe Args in the navigation editor

On the right, you’ll notice the Arguments tab, which has a + button to its right. Click the button to add the first argument, the promo code. In the Add Argument dialog, do the following:

  1. Set its name to promoCode.
  2. Select its type to String.
  3. Set it to Nullable.
  4. Set its default value to @null since the argument is optional.

Click Add. Congrats, you just created your first argument!

Defining Safe Args

Now, switch to the Code window by selecting it at the top-right corner and notice that inside ConfirmationFragment, a new argument appears:

  android:defaultValue="@null" />

That’s quite readable and straightforward. :]

Switch back to the Design window and add the add-ons argument. Call it travelAddOns, set its type to Integer since it should contain multiple values and set it to be an array. Once added, there should be a new argument as follows:

  app:argType="integer[]" />

There goes your second argument!

Adding a Custom Type Argument

It’s time to create the last argument for the traveler’s information, but what would its type be? It should be of type TravelerInformation, which is a data class that’s in the project. Remember that to pass it with Safe Args, it has to be one of the supported types. You’ll have to make TravelerInformation a Parcelable. To do this, add the following plug-in to the app-level build.gradle:

apply plugin: "kotlin-parcelize"

After syncing the project, open TravelerInformation.kt and make the class a Parcelable. Annotate it with @Parcelize and have it implement the Parcelable interface. The class should now be as follows:

data class TravelerInformation(
    val fullName: String,
    val age: Int,
    val passportNumber: String
): Parcelable

In the code above, adding @Parcelize generates the code required to make TravelerInformation parcelable.

You’re now ready to set TravelerInformation as an argument type.

Go back to navigation_graph.xml and create the last argument for the traveler’s information. Call it travelerInformation, select the argument type custom parcelable, select the class TravelerInformation and click Add. Build the project and let Safe Args do its magic.