Navigation library in Android
Tags: android, jetpack, navigation
Published: 2019-11-27 13:24:03


<p>At Google I/O 2018, Android introduced a bunch of new components to the Android Jetpack libraries. One such library is <a href="https://developer.android.com/guide/navigation">Navigation component</a>, designed to reduce the effort in building apps with consistent navigation flow and to reduce errors and making it easier to work fragments. Recently the Navigation Component moved from beta to stable.</p>

<p>With the navigation component, it's very easy to build consistent navigation in your apps. Not only this with the navigation component you can do a lot more:</p>



<ul>
<li>Fragment transaction can be done with just a single method call.</li><li>Handling Up and Back actions correctly by default.</li><li>Safely pass data between destination with <a href="https://developer.android.com/topic/libraries/architecture/navigation/navigation-pass-data#Safe-args">SafeArgs</a>.</li><li>Native support for deep-linking.</li><li>Building navigation drawers &amp; bottom navigation bars with minimal code.</li>
</ul>


<p>So now let's learn how we can use this component in our apps.</p>

<h3>1. Add the dependencies</h3>

<p>In your app-level <code>build.gradle</code> file include the following dependencies</p>

```gradle
implementation "androidx.navigation:navigation-fragment:2.1.0"
implementation "androidx.navigation:navigation-ui:2.1.0"
```


<p>If you are using kotlin append <code>-ktx</code> to the above libraries</p>

```gradle
implementation "androidx.navigation:navigation-fragment-ktx:2.1.0"
implementation "androidx.navigation:navigation-ui-ktx:2.1.0"
```

<p>To add support for SafeArgs, add a classpath in your project-level ```build.gradle``` file.</p>

```gradle
buildscript {
    repositories {
        google()
    }
    dependencies {
        //.....
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0"
    }
}
```


<p>Now add the following line to your app-level ```build.gradle``` file.</p>


```gradle
apply plugin: "androidx.navigation.safeargs"
```

<h3>2. Add Activity</h3>


<p>Create a <code>BaseActivity</code> to contain the fragments. This activity will contain the Host fragment.</p>


<h4>Java: </h4>


```java
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base);
    }
}
```


<h4>Kotlin: </h4>


```kotlin
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_base)
    }
}
```


<p>Now add a layout file <code>activity_base.xml</code> that contains a fragment. This fragment will be our NavHost fragment i.e, An empty container to display our destination fragments.</p>


```xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.BaseActivity">

    <fragment
        android:id="@+id/base_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:defaultNavHost="true" />

</androidx.constraintlayout.widget.ConstraintLayout>
```


<p> <code>android:name</code> signifies that this fragment is a host for our destination and <code>app:defaultNavHost</code> when set to true tells that this is the default host for all the destination in our app.</p>


<h3>3. Add the Navigation Graph</h3>


<p>Navigation graph is an XML resource file that contains all the navigation-related information in a single file. It contains all the information about destinations and paths. It can be visually edited from Android Studio 3.3 onwards.</p>


<p><strong>To add the navigation graph:  Right-click on the resource(res) folder in the Project menu&gt; select New &gt; select Android Resource File.</strong></p>


<div class="wp-block-image"><figure class="aligncenter"><img src="https://pushkaranand.me/blog/wp-content/uploads/2019/09/Screenshot-from-2019-09-24-23-03-44.png" alt="" class="wp-image-153"/><figcaption>Select navigation from the Resource type dropdown and add the filename nav_graph.xml</figcaption></figure></div>


<div class="wp-block-image"><figure class="aligncenter"><img src="https://pushkaranand.me/blog/wp-content/uploads/2019/09/Screenshot-from-2019-09-24-23-20-16-1024x469.png" alt="" class="wp-image-160"/><figcaption>A visual editor opens up to edit the navigation graph file.</figcaption></figure></div>


<p>Now add this graph file to the NavHost fragment we just created above as <code>app:navGraph="@navigation/nav_graph"</code> </p>


```xml
   <fragment
        android:id="@+id/base_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph"
        />
```


<h3>4. Create Destinations</h3>


<p>On the navigation graph editor find the add destination button and then click on 'Create new Destination'.</p>


<div class="wp-block-image"><figure class="aligncenter"><img src="https://pushkaranand.me/blog/wp-content/uploads/2019/09/Screenshot-from-2019-09-24-23-25-31.png" alt="" class="wp-image-162"/><figcaption>The first icon with a plus sign is the add destination.</figcaption></figure></div>


<p>Now a fragment creation window opens up. Let's name our fragment HomeFragment.</p>


<div class="wp-block-image"><figure class="aligncenter"><img src="https://pushkaranand.me/blog/wp-content/uploads/2019/09/Screenshot-from-2019-09-24-23-28-51.png" alt="" class="wp-image-163"/></figure></div>


<p>Set the HomeFragment as our start destination by using the home icon in the toolbar.</p>


<p>Now let's add another destination and name it DestFragment. Now our navigation graph looks like below.</p>


<div class="wp-block-image"><figure class="aligncenter"><img src="https://pushkaranand.me/blog/wp-content/uploads/2019/09/Screenshot-from-2019-09-24-23-40-04-1024x467.png" alt="" class="wp-image-164"/><figcaption>After creating two destinations.</figcaption></figure></div>


<p>Click on the homeFragment destination and drag a path from homeFragment to destFragment destination. </p>


<div class="wp-block-image"><figure class="aligncenter"><img src="https://pushkaranand.me/blog/wp-content/uploads/2019/09/Screenshot-from-2019-09-24-23-42-00.png" alt="" class="wp-image-165"/><figcaption>Drag a path from home to dest.</figcaption></figure></div>


<p>Let's add a button to our HomeFragment. When clicking the button the DestFragment should open.</p>


<p>Go to <code>fragment_home.xml</code> &amp; Add a button</p>


```xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".HomeFragment">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Open DEST"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    
</androidx.constraintlayout.widget.ConstraintLayout>
```

<p style="text-align:left">Now in <code>HomeFragment.kt</code> or <code>HomeFragment.java</code> file override the <code>onViewCreated</code> method and set a listener for the button we just added. Then use the navigate method of NavController object to switch to destFragment destination.</p>


<h4>Java</h4>


```java
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;

public class HomeFragment extends Fragment {


    public HomeFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        final NavController navController =
                Navigation.findNavController(requireActivity(), R.id.base_fragment);

        Button button = getActivity().findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                navController.navigate(R.id.destFragment);
            }
        });
    }
}
```


<h4>Kotlin</h4>


```kotlin
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.fragment_home.*

class HomeFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        button.setOnClickListener { 
            findNavController().navigate(R.id.destFragment)
        }
    }
}

```


<p>This is it. See how easy it is to switch fragments. I'll write about using navigation graph with BottomNavigationBar in my next post in the series. </p>


<p>You can find the sample code used in this article <a href="https://github.com/pushkar-anand/NavGraphExample">here</a>.</p>


Originally published at [A coder’s words](https://pushkaranand.me/blog/2019/09/25/androidx-jetpack-navigation-in-android/).