Android Navigation Components Tutorial

Introduction

The Google I/O 2018 had many interesting topics, many of them got a lot of attention, but the most exciting one for me was the Android Navigation Component. I think it was mostly because this topic is inevitable each time you start a project or refactor some good old apps. There were many approaches, which became popular, but all of them depend on third party libs. But from now on (or from the first stable release in the future), we will have a great tool in our hands, which is maintained by Google???

If you want to use Navigation components with Android Studio, you need a version of 3.2 Canary 14 or a newer release.

android navigation androidx

Getting Started

To get things working, first we have to make sure to import Navigation Components core to our module:

The next step is to plan and create our navigation graph. For the planning part, you can find help in the documentation of the Navigation Components here or in this great article. If you’re ready with the design, the next step is to create a nav_graph.xml resource under res/navigation in your project. This contains three different types of items:

  • Destination: Points to a Screen or View in your project.
  • Acton: Contains information about the target destination and the information which needs to be exchanged.
  • Host: Manages the navigation between destinations.

If you created your navigation XML resource, you can start declaring your Destinations (Activities, Fragments).

You can do this by writing the XML by hand or using the Navigation Editor bundled in the new Canary versions of Android Studio 3.2. You will notice that the root navigation element also has an attribute indicating the starting Destination. If you have declared most of your destinations, you can specify Arguments and Actions for them. A fully described destination looks something like the example below:

The last missing part is the Host, which will use our navigation graph. The navigation host is responsible for switching between nodes of the graph (this involves fragment transactions, passing the bundled arguments, back navigation handling, etc.) and provides a NavController interface. This interface can be used to send Actions to the host to change it’s state. To provide a host we need an Activity, which will contain our NavHostFragment. The NavHostFragment is a default NavHost implementation provided by the Navigation component’s core. To use this component you can define you MainActivity’s layout like this:

As you can see, it’s a simple fragment, but it has two additional attributes: app:defaultNavHost=”true” and app:navGraph=”@navigation/nav_graph”. The app:navGraph is used to associate a navigation graph resource with this NavHost. The app:defaultNavHost indicates whether or not it should intercept the system back button events. If everything goes well, you will have a working base app which displays the starting Destination of your defined navigation graph. To try out the navigation mechanism, you will need to find the NavController provided by the NavHostFragment in your MainActivity instance. This can be achieved by a simple call shown below:

But most of the time, you will want to initiate a navigation Action from your graph’s Fragments, therefore to get the Host’s NavController in a Fragment instance you can use the NavHostFragment.findNavController(your_fragment_instance) method.

Integration with Views

One module of the Navigation Component provides built-in functions for configuring common Views used. This functionality can be configured through the NavigationUI class, which can be imported using the following dependency:

With this class you can connect your NavController with your ActionBar, DrawerLayout, NavigationView or ButtomNavigationView.


If you connect your NavigationViews to the NavController and the menu XML resources have matching item IDs with the destinations declared in the navigation graph, then this will automatically handle highlighting the item associated with the current destination displayed. It will also handle executing navigation actions based on the NavigationView’s selected item.The behavior and the config method are the same for BottomNavigationViews.

Configuring the ActionBar with the NavController will result in displaying the destination labels as title, and it will also provide the hamburger icon and the back arrow according to the current destination’s position in the graph. It also handles the opening and closing of the Drawer if the DrawerLayout is also provided for the config.

DeepLinking

The Navigation Component has built-in support for DeepLinks. You can specify deepLink Uri-s in your navigation graph’s XML for your destinations. It’s simple as below:

If you want your app’s Activity to respond for the Uri specified in your nav_graph.xml, you must add it in your manifest, like an intent-filter, for your Activity.

Simple as that. But we can even get arguments from our Uri by including placeholder is the path.


In this case our destination will receive a Bundle containing the placeholder value associated with a „page_number” key. We can have multiple placeholders in one Uri and we can also inclue wildcards („.*” indicating zero or more characters).

SafeArgs Plugin

This is my most favourite tool of the whole Navigation Component, because it makes parameterized navigations so easy. Having lots of screens in one app (or lots of apps in progress with some screens) can easily make you forget some of the mandatory arguments, which will lead to unexpected runtime crashes during development.

Thanks to the SafeArgs plugin; if you declare your arguments in the navigation graph, you will always see the parameters on the generated NavDirection builders.

The example above shows a destination having two arguments. A groupId describing which list should be requested and a limit describing the max count of the request’s result. If you investigate it closely, you can see that the limit has a defaultValue specified.

The generated Directions code will look something like this.

As you can see, the plugin used the default value for the limit and generated a NavDirections implementation with a constructor, which has the mandatory arguments (Which don’t have default values, so you must provide them.). You can construct a navigation to this destination without using this helper class, but I strongly recommend using it, because it has an implementation on the receiving side also, which will extract your passed arguments from the Bundle, and validate the passed data. The next snippet shows the generated class which can be used to unwrap the bundled arguments.

As we can see, if we target this destination without suppling the declared arguments, then the fromBundle method will throw an IllegalArgumentException indicating that there was a missing argument. This can only occur with arguments that don’t have default values.

To wrap things up, the SafeArgs plugin can make our life easier when we need to pass information to destinations.

Current limitations:

Only application modules are supported by the plugin, which means if you have your project divided into submodules that invole Fragments outside the application module, the SafeArgs plugin won’t be able to generate the classes. Hopefully this will be fixed soon. (https://issuetracker.google.com/issues/80036553https://issuetracker.google.com/issues/110011752)

Also in modularized projects, you will probably want to create navigation sub graphs, which will be „included” in a top level navigation graph. This can be a pain if you haven’t gone through some SO searches, due to the lack of documentation.

Overview

I really enjoyed diving into this new tool. The basics can be understood by walking through the provided tutorials on Android Developers (https://developer.android.com/topic/libraries/architecture/navigation/). There are a few limitations that will probably make some of the developers hesitate about using this in the near future, but hey, it’s only in the alpha stage, so there’s no need to worry. I’m really looking forward to using it in future projects, but I will also wait at least for the first beta version. 😉


Wanari is an 18-year-old custom software development company, based in downtown Budapest, Hungary. We aim at making the world a better place by creating software even our picky selves would use. For more, visit us at: https://www.wanari.com/.