Jetpack Architecture Component - Navigation In Android

Introduction

 
Android Navigation has changed a lot over the years. We used to  manage backstack in fragments manually and it was a very tedious task. Putting fragments in a stack, pushing one and popping another, was the process. Let's see an image which explains all the components.


Notice  the Architecture section -- the  green one on the left, and it has various components like Navigation, Paging, Room etc.
 

Set up environment to use navigation


Include navigation support in build.gradle file of app level by adding the following dependencies.
  1. apply plugin: 'com.android.application'  
  2.   
  3. android {  
  4.     compileSdkVersion 29  
  5.     buildToolsVersion "29.0.3"  
  6.   
  7.     defaultConfig {  
  8.         applicationId "com.example.navigationsample"  
  9.         minSdkVersion 21  
  10.         targetSdkVersion 29  
  11.         versionCode 1  
  12.         versionName "1.0"  
  13.   
  14.         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"  
  15.     }  
  16.   
  17.     buildTypes {  
  18.         release {  
  19.             minifyEnabled false  
  20.             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'  
  21.         }  
  22.     }  
  23.   
  24. }  
  25.   
  26. dependencies {  
  27.     implementation fileTree(dir: 'libs', include: ['*.jar'])  
  28.   
  29.     implementation 'androidx.appcompat:appcompat:1.1.0'  
  30.     implementation 'com.google.android.material:material:1.1.0'  
  31.     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'  

  32.    // Java implementation of navigation
  33.     implementation 'androidx.navigation:navigation-fragment:2.2.1'  
  34.     implementation 'androidx.navigation:navigation-ui:2.2.1'        

  35.     implementation 'androidx.legacy:legacy-support-v4:1.0.0'  
  36.     testImplementation 'junit:junit:4.12'  
  37.     androidTestImplementation 'androidx.test.ext:junit:1.1.1'  
  38.     androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'  
  39. }  
Navigation has mainly three parts to make proper navigation as described below.
  • Navigation graph
    An XML resource that contains all navigation-related information in one centralized location. This includes all of the individual content areas within your app, called destinations, as well as the possible paths that a user can take through your app.

  • NavHost
    An empty container that displays destinations from your navigation graph. The Navigation component contains a default NavHost implementation, NavHostFragment, that displays fragment destinations.

  • NavController
    An object that manages app navigation within a NavHost. The NavController orchestrates the swapping of destination content in the NavHost as users move throughout your app.
Benefits of Navigation component
  • This architecture handles up navigation atomatically.
  • Provides support for animations by default.
  • Implementing and handling deep links.
  • Including Navigation UI patterns, such as navigation drawers and bottom navigation, with minimal additional work.
  • Pass data between destinations ie. fragments safely

Getting started with a sample app creation

 
Step 1
 
Let's create a sample application with basic activity template selection.

 
We are taking basic activity because it will create two fragments by default and a main activity.
 
Step 2

Name project as Navigation sample.

 
Step 3

After the successfull build then it will generate a navigation graph for you. Create a third fragment name it "ThirdFragment" and place it in a navigation graph. See your nav_graph.xml file.

 
Navigation Graph
 
A navigation graph is a resource file that contains all of your destinations and actions. The graph represents all of your app's navigation paths. 
 
First let's see the nav_graph.xml and arrangement of fragments in the order they traverse.
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <navigation xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     xmlns:tools="http://schemas.android.com/tools"  
  5.     android:id="@+id/nav_graph"  
  6.     app:startDestination="@id/FirstFragment">  
  7.   
  8.     <fragment  
  9.         android:id="@+id/FirstFragment"  
  10.         android:name="com.example.navigationsample.FirstFragment"  
  11.         android:label="@string/first_fragment_label"  
  12.         tools:layout="@layout/fragment_first">  
  13.   
  14.         <action  
  15.             android:id="@+id/action_FirstFragment_to_SecondFragment"  
  16.             app:destination="@id/SecondFragment" />  
  17.     </fragment>  
  18.     <fragment  
  19.         android:id="@+id/SecondFragment"  
  20.         android:name="com.example.navigationsample.SecondFragment"  
  21.         android:label="@string/second_fragment_label"  
  22.         tools:layout="@layout/fragment_second">  
  23.   
  24.         <action  
  25.             android:id="@+id/action_SecondFragment_to_FirstFragment"  
  26.             app:destination="@id/ThirdFragment" />  
  27.     </fragment>  
  28.   
  29.   
  30.     <fragment  
  31.         android:id="@+id/ThirdFragment"  
  32.         android:name="com.example.navigationsample.ThirdFragment"  
  33.         android:label="@string/first_fragment_label"  
  34.         tools:layout="@layout/fragment_third">  
  35.   
  36.         <action  
  37.             android:id="@+id/action_SecondFragment_to_ThirdFragment"  
  38.             app:destination="@id/FirstFragment" />  
  39.     </fragment>  
  40. </navigation>  
To understand the above code, first see the parent tag which consists of action .
  • Destinations are the different content areas in your app.
  • Actions are logical connections between your destinations that represent paths that users can take.
 
Now let's see the code of all fragments and activity to see how navigation is working after navigation graph. Here comes the role of NavController.
 
FirstFragment.java 
  1. public class FirstFragment extends Fragment {  
  2.   
  3.     @Override  
  4.     public View onCreateView(  
  5.             LayoutInflater inflater, ViewGroup container,  
  6.             Bundle savedInstanceState  
  7.     ) {  
  8.         // Inflate the layout for this fragment  
  9.         return inflater.inflate(R.layout.fragment_first, container, false);  
  10.     }  
  11.   
  12.     public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {  
  13.         super.onViewCreated(view, savedInstanceState);  
  14.   
  15.         view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {  
  16.             @Override  
  17.             public void onClick(View view) {  
  18.                 NavHostFragment.findNavController(FirstFragment.this)  
  19.                         .navigate(R.id.action_FirstFragment_to_SecondFragment);  
  20.             }  
  21.         });  
  22.     }  
  23. }  
See the click listener event  -- when button is clicked in the above code then there is a class called NavHostFragment. Find the controller and navigate to the destination as action is defined  as what to do.

SecondFragment.java
  1. public class SecondFragment extends Fragment {  
  2.   
  3.     @Override  
  4.     public View onCreateView(  
  5.             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  6.         // Inflate the layout for this fragment  
  7.         return inflater.inflate(R.layout.fragment_second, container, false);  
  8.     }  
  9.   
  10.     public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {  
  11.         super.onViewCreated(view, savedInstanceState);  
  12.   
  13.         view.findViewById(R.id.button_second).setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View view) {  
  16.                 NavHostFragment.findNavController(SecondFragment.this)  
  17.                         .navigate(R.id.action_SecondFragment_to_FirstFragment);  
  18.             }  
  19.         });  
  20.     }  
  21. }  
ThirdFragment.java
  1. public class ThirdFragment extends Fragment {  
  2.   
  3. @Override  
  4.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  5.                              Bundle savedInstanceState) {  
  6.         // Inflate the layout for this fragment  
  7.         return inflater.inflate(R.layout.fragment_third, container, false);  
  8.     }  
  9.   
  10.     public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {  
  11.         super.onViewCreated(view, savedInstanceState);  
  12.   
  13.         view.findViewById(R.id.button_third_fragment).setOnClickListener(new View.OnClickListener() {  
  14.             @Override  
  15.             public void onClick(View view) {  
  16.                 NavHostFragment.findNavController(ThirdFragment.this)  
  17.                         .navigate(R.id.action_SecondFragment_to_ThirdFragment);  
  18.             }  
  19.         });  
  20.     }  

Conclusion


Now after seeing the code of all the fragments It seems there is no backstack maintained in the project. That is the beauty of navigation component. This article mainly emphasized the nav_graph.xml file and their actions  -- this is the navigation. You can see the fragment code and see there is no backstack.