Using Jetpack Navigation Component in Android
In this blog, we are going to learn how to integrate the navigation component, how to see the complete navigation graph of our application, and how to pass arguments safely.
The Navigation Architecture Component simplifies implementing navigation, while also helping you visualize your app’s navigation flow. The library provides a number of benefits, including:
- Automatic handling of fragment transactions
- Correctly handling up and back actions by default
- Default behaviors for animations and transitions
- Deep linking as a first-class operation
- Implementing navigation UI patterns (like navigation drawers and bottom nav) with little additional work
- Type safety when passing information while navigating
- Android Studio tooling for visualizing and editing the navigation flow of an app
The Navigation component requires Android Studio 3.3 or higher and is dependent on Java 8 language features .
Overview
The Navigation Component consists of three key parts:
- Navigation Graph (New XML resource) — This is a resource that contains all navigation-related information in one centralized location. This includes all the places in your app, known as destinations , and possible paths a user could take through your app.
- NavHostFragment (Layout XML view) — This is a special widget you add to your layout. It displays different destinations from your Navigation Graph.
-
NavController (Kotlin/Java object)
— This is an object that keeps track of the current position within the navigation graph. It orchestrates swapping destination content in the
NavHostFragment
Integration
Just include the following code in the dependencies block of your module-level
build.gradle
file
def nav_version = "2.2.2"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
Navigation Graph
First, we will create a file that will contain our navigation graph. In the res, directory create a new android resource file as follows
This will create an empty resource file named
nav_graph.xml
under the navigation directory.
For the sake of demonstration, I have created a sample app that contains two fragments named FirstFragment and SecondFragment. FirstFragment has a button on click of which we will navigate to the SecondFragment.
We define these fragments in the navigation graph as below
<navigation 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:id="@+id/nav_graph"
app:startDestination="@id/nav_first_fragment">
<fragment
android:id="@+id/nav_first_fragment"
android:name="app.navigationcomponentexample.FirstFragment"
tools:layout="@layout/fragment_first">
<action
android:id="@+id/action_first_to_second"
app:destination="@id/nav_second_fragment"/>
</fragment>
<fragment
android:id="@+id/nav_second_fragment"
android:name="app.navigationcomponentexample.SecondFragment"
tools:layout="@layout/fragment_second"/>
</navigation>
Here the root tag named
navigation
has a parameter called
app:startDestination
which has the id of our first fragment. This defines that the first fragment will be loaded in the NavHostFragment automatically
The Navigation Component introduces the concept of a destination. A destination is any place you can navigate to in your app, usually a fragment or an activity. These are supported out of the box, but you can also make your own custom destination types if needed.
Notice that for first fragment we have defined an action with the following attributes:
android:id="@+id/nav_first_fragment"
app:destination="@id/nav_second_fragment"
Each action should have a unique id which we will use to navigate to the required destination.
Here the destination points to the id of the second fragment defined in the nav graph, which means that with this action we will navigate to the second fragment.
After this step when you open the nav_graph.xml and switch to the design tab, it should look like the following.
Navigation types
With the navigation component, we have multiple ways to navigate
1. Navigation using destination Id
We can provide the id of the destination fragment to navigate to it, like the following
button.setOnClickListener {
findNavController().navigate(R.id.nav_second_fragment)
}
2. ClickListener
For views, we can also use createNavigateOnClickListener () method from the Navigation class as follows
button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.nav_second_fragment, null))
3. Navigation using Actions
As in the above nav graph, we have defined action in the first fragment, we can use the id of the action as follows
button.setOnClickListener {
findNavController().navigate(R.id.action_first_to_second)
}
The last piece required is to define the NavHostFragment. It is a special widget that will display the different destinations defined in the nav graph. Copy the following code and paste it in the layout of the activity in which we want to load our FirstFragment.
<fragment
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true"/>
defines the NavHostFragment used by NavController
android:name="androidx.navigation.fragment.NavHostFragment"
is simply stating that you want this to be the NavHost that intercepts and works as the back button on your device.
app:defaultNavHost="true"
associates the
app:navGraph="@navigation/app_navigation"
with a navigation graph. This navigation graph specifies all the destinations the user can navigate to, in this
NavHostFragment
NavHostFragment
After these steps when you run the app, FirstFragment should be loaded automatically and when you click the button it should open the SecondFragment. Also when you press the back button, it should navigate back to the FirstFragment.
That’s it. We have a working example of the Navigation Component. In the next section, we will discuss how to pass arguments while navigating to the fragments in a safe manner.
Safe Arguments
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.
Safe args allows getting rid of the code like below
val username = arguments?.getString("usernameKey")
with the following
val username = args.username
Integration
Add the following code in the top-level Gradle file:
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.2.2"
Now import the plugin into the module level Gradle file:
apply plugin: 'androidx.navigation.safeargs.kotlin'
Now the safe args plugin is active in your project. We will add 2 arguments to be passed to the SecondFragment from the FirstFragment. We will define arguments in the nav graph as follows
<fragment
android:id="@+id/nav_second_fragment"
android:name="app.navigationcomponentexample.SecondFragment"
tools:layout="@layout/fragment_second">
<argument
android:name="arg1"
app:argType="integer"
android:defaultValue="0"/>
<argument
android:name="arg2"
app:argType="string"
android:defaultValue="default"/>
</fragment>
Here the first argument is named arg1 which is of type Integer and has the default value of 0. Similarly, the second argument is named arg2 which is of type String and has a default value of “default”.
After we define these arguments, Gradle will generate a class named SecondFragmentArgs which can be used in SecondFragment to retrieve the arguments in the following way.
val safeArgs: SecondFragmentArgs by navArgs()
val arg1 = safeArgs.arg1
val arg2 = safeArgs.arg2
Here we are assured that arg1 is of type Integer and arg2 is of type String and thus we don’t need to cast them to their respective types.
Now in order to pass these arguments from the FirstFragment, another class named FirstFragmentDirections gets created which has a static method named actionFirstToSecond . This can be used to pass the arguments in the following way
button.setOnClickListener {
val directions = FirstFragmentDirections.actionFirstToSecond(arg1 = 1234, arg2 = "abcd")
findNavController().navigate(directions)
}
That’s all is required to pass arguments in a type-safe manner. Apart from the inbuilt types, you can also define the custom type of arguments by creating a Parcelable class.
I hope you have found this article helpful. You can access the source code for the sample app from here .
Happy learning.