Navigating around an app is an absolutely fundamental part of Android development. Historically, this is performed using intents or fragment transactions, which in simple cases, like clicking a button, was easy enough. But what if you wanted to do something just slightly more complex? For example, something like hooking up a common pattern like bottom navigation. Let us refer to this image of a standard navigation bar for a better understanding.
Coming back to the previous question, if we need to do something more complex, we have to ensure that not only does the bottom navigation view actually navigate, but it also highlights the correct button. Furthermore, it uniformly handles the back stack and ensures that users don’t end up getting lost or confused. Cases like these are where the new navigation component shines. The navigation component is a collection of libraries, a plugin & tooling that simplifies android navigation.
Navigation Component: An Overview
Beyond making the setup for common patterns like bottom navigation easier, the navigation component performs the following:
- It handles the back stack and fragment transactions.
- Takes care of argument passing.
- Helps in navigation based animations.
- Handles deep linking.
Most importantly, it gathers up all this navigation information and puts it in one visualized location in your app, the navigation graph. The navigation component works out of the box with fragments and activities. One could also extend the library to work with other screen implementations like custom views. Let’s take a look at some examples of the navigation components in action, with a single activity swapping out multiple fragments. The navigation component has three major components working together in harmony. These are the Navigation Graph, NavHostFragment, and NavController.
The Navigation Graph
The navigation graph is a new resource type. It’s an XML file that contains and centralizes information related to navigation. This information can be visualized in the new navigation editor that is available in Android Studio 3.3 and above. It’s a graphical editor used to create this navigation graph. Each of these screens is called destinations or places that you can navigate to. In this example, they’re all fragments. Take a look at the image of the navigation graph, given below.
Now, the arrows shown in the image here are called ‘actions,’ and they represent a different path that a user could take through your app. If you click on one of the actions, you can see a whole bunch of embedded information, including data path between destinations, transition animations back stack manipulation, and so on. Clicking on the destination, you can see things like deep link URLs and watch options. This is all part of the XML of the graph.
NavHostFragment is a fragment widget that will add to your layout, assuming you are doing fragment navigation.
It’s basically a window that swaps in and out, different fragment destinations, that are included in your navigation graph. The final piece of the puzzle is the NavController. Each NavHostFragment has a navcontroller that we use in our Kotlin or Java code.
The NavController is what instructs the navigation to occur. So, if one writes some code, the navcontroller will then perform this navigation action based on the information that was in the navigation graph, and it will ultimately swap out the fragment that is shown in the NavHostFragment.
Now we are using the action’s XML id to specify which of those action arrows to follow. But an even better way to do this is using the navigation components Safe Args plugin. The Safe Args plugin generates code to allow one to use type-safe navigation and argument passing. First, add the Gradle plug-in to your code. This will generate classes based on your navigation graph. It’ll make direction classes for any destination that has actions & it will make argos classes for any destination with arguments. If the original navigation statement is taken, one can swap these generated classes, and you’ll get something that looks like this.
Instead of referring to an action by its XML id, we are making sure that we have an action that’s actually associated with the destination. One can also set arguments for the action, pass in the wrong type, and the code won’t compile. Getting the argument that you passed through is easy. Simply use the GeneratedArgs class, and you will have type-safe access to the correctly named arguments only. This means that one need not worry about the key-value pairs of yesteryear.
Now that we have discussed simple navigation, let us move on to discuss about setting up the bottom navigation bar. The navigation component includes an additional navigation UI library in Java, and KTX extensions for Kotlin, that have support for option menus, bottom navigation view, and navigation drawer. It also works with an action bar, toolbar, and collapsing toolbar. For our bottom navigation, one has to add the bottom nav to the XML as usual. We could also create an XML menu with IDs that match the XML IDs of our destinations and our navigation graph, that we want the bottom navigation to go to. Then we could use the navigation UI to wire up the rest. In Kotlin, that’s done with this handy extension function.
This one line of code has the NavController handle the actual navigation while making sure to follow material design best practices as far as back-stack management goes. Additionally, it handles highlighting the correct bottom buttons.
The world is always on the lookout for new ideas and inventions that simplify and transform our lives. The introduction of the navigation component is one such groundbreaking idea. It is undeniable that it has made one of the crucial yet unavoidable parts of the android development lifecycle easier, intuitive, and more user friendly for the developers. By simplifying the development process and ensuring consistency and predictability in the user experience, the navigation component has definitely emerged as a winner.
Senior Software Engineer, RapidValue