Using Safe Args With the Android Navigation Component
- Getting Started
- Why Safe Args?
- Adding Safe Args to Your App
- Passing Data With Safe Args
- Defining an Argument in a Destination
- Adding a Custom Type Argument
- Retrieving Arguments in a Destination
- Defining an Argument in an Action
- Sending Arguments From a Destination
- Safe Args and Proguard
- Where to Go From Here?
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.
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.
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.
Now that you see why Safe Args is useful for your project, it’s time to implement it.
Adding Safe Args to Your App
To add Safe Args to your project, include the following classpath in your top-level build.gradle:
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:
- resource reference
Primitive types —
bool — back
Boolean respectively on the JVM, so they can’t be null. In contrast,
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
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:
- Set its name to promoCode.
- Select its type to String.
- Set it to Nullable.
- Set its default value to
@nullsince the argument is optional.
Click Add. Congrats, you just created your first argument!
Now, switch to the Code window by selecting it at the top-right corner and notice that inside
ConfirmationFragment, a new argument appears:
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:
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
Parcelable. To do this, add the following plug-in to the app-level
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
In the code above, adding
@Parcelize generates the code required to make
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.