On the last Google IO, there was an announcement of JetPack — a set of libraries to help and boost the Android development. These libraries are bringing the development of the essential parts of an application to a completely new level. By essential parts I mean things like handling configuration change, persisting data, executing operations in the background and so on. Some of those libraries were announced at Google IO 2017, and by now are having a stable release, and some of them are completely new. One of the new libraries is the Navigation.

What is Navigation

The Navigation component is a new architecture component that is supposed to simplify the implementation of the navigation in an application. At the very beginning, it’s important to mention that the Navigation component is scoped to a single Activity. It means that it embraces the idea of using single activity with multiple fragments for navigating through different parts of the application. So, an Activity(preferably an entry point into the application) would contain a Navigation component. Then, one of the fragments of this Activity could potentially point to another Activity, which would have to define its own Navigation scope. Now, this does sound a little bit tricky because of the well-known problems with the fragments and the fragment manager, but the good news is that this Navigation component is there to do these things for us. So the fragment management is done by itself.

Why navigation

This is one of the first questions that come to mind when thinking about the Navigation component. As mentioned earlier, there was a well-known problem with the fragments and many developers were trying to avoid using fragments, or at least avoid working with the Fragment Manager. Turns out, the need of such component lays in the fact that the activities are having some limitations too.

Fair enough, the arguments that Ian Lake points out in this tweet are more than enough to think about making more robust and easy to use solution. The Navigation component is not only helping to sort out those problems mentioned by Ian Lake in that tweet, but it brings some awesome features like safe arguments passing, default arguments, handling deep links, automatic setup with side NavigationView and with the BottomNavigationView. Furthermore, there is also a visual editor where all these things can be wired up together, and the developers can take an overview of what’s going around and understand and manage the structure lot easier. Let’s take a closer look.

Getting Started

I would highly recommend the official guide for the new Navigation component, as well as its documentation to get rolling with the implementation.

I’ve created a simple playground project where I was trying various things with the Navigation component. Keep in mind that I am using the latest version of Android Studio from the Canary Channel.

To begin with, we have to declare the Navigation component dependencies in our build file, followed by sync:

implementation 'android.arch.navigation:navigation-fragment-ktx:1.0.0-alpha01' implementation 'android.arch.navigation:navigation-ui-ktx:1.0.0-alpha01'

Define Navigation Graph

In order to start with the Navigation component, we have to first define the navigation graph. The navigation graph is nothing but an XML file that is getting placed in the navigation folder in the resources. With a right-click on the res folder, we choose New -> Android Resource File

Add new resource file

Then, in the New Resource File window, we specify a name for the file, followed by choosing Navigation as Resource type

Define new navigation graph resource file

Once done, the newly defined navigation graph is getting opened with the navigation editor in the studio. By using the latest Android Studio we are able to see this XML file in design preview as well as edit the XML as text. The same that we could do with the layout files. The navigation editor provides an ability to wire the things up and configure the navigation in the desired way.

Empty navigation graph in the navigation editor

Next, there is a need for a host fragment to be defined. In the example I shared, we have an Activity that has a layout named activity_main where this host fragment is defined. In this layout, we also include a BottomNavigationView, in order to investigate some interesting things how the new Navigation component works with it.

We see 2 new attributes in the definition of the host navigation fragment: app:defaultNavHost="true" and app:navGraph="@navigation/navigation_graph".

The former one makes sure that the NavHostFragment intercepts the system Back button. In our activity we also have to overwrite onSupportNavigateUp() method as follows:

class MainActivity : AppCompatActivity() {

...

override fun onSupportNavigateUp() =

findNavController(R.id.mainNavigationFragment).navigateUp()

}

The latter one is used to define which navigation graph from the navigation resources folder is going to be assigned to the NavHostFragment. Once we define that in the XML, we could get back to the navigation editor in the studio. As we can see, now it displays the host as expected:

Host of the navigation graph

Now we can go on and some destinations in the navigation graph, directly in the navigation editor

Create new destination window

For our case, I defined 4 destinations. The first three to serve the BottomNavigationView we have in the main_activity , and the fourth one to be used as a detailed preview that will get opened after a click on an action. Here is how it looks in the navigation editor

Navigation editor

Then, as mentioned before, to make this setup work with the BottomNavigationView, we need a very little effort. As we can find out in in the navigation graph, the items we defined in it are having id attributes

By simply making the ids of the menu items for the BottomNavigationView same as these ids in the navigation graph, the setup is almost done. An important note on this is that this can be used for menu items in a side NavigationView drawer, Toolbar’s menu items, and BottomNavigationView menu items. It does not, however, work for the popup menus. There are just two lines of code that we have to add in the activity to wire them up, so that clicking on a particular menu item will navigate to the desired destination.

val navController = findNavController(R.id.mainNavigationFragment)

bottomNavigationView.setupWithNavController(navController)

But, since we also have a toolbar, we also want to set up the toolbar with the navigation, so when we navigate to a new screen, we would like to update the Toolbar’s title. To achieve that, we add one more line

setupActionBarWithNavController(navController)

This line is a Kotlin extension function on the AppCompatActivity class. Eventually, the activity’s code became like this:

With a very little effort we made the navigation work together with the BottomNavigationView and the Toolbar.

As mentioned before, the call to setupActionBarWithNavController is an extension function, and here is how it is defined:

fun AppCompatActivity.setupActionBarWithNavController(

navController: NavController,

drawerLayout: DrawerLayout? = null

) {

NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)

}

It’s interesting that optionally, we could pass in that function a DrawerLayout if we had one. So it will set up both the Toolbar and the side NavigationView to work with the Navigation. However, there is no option to pass a BottomNavigationView and it has to be done by making that additional call in the activity. I was wondering why is that, and I did a little investigation, and the result is the following.

Guideline Updates

If you check out and try out the example I shared, you will notice a very weird thing. Mainly, the app opens the home destination as we have set it before, but if you try to open some of the other sections on the bottom navigation, it will display its fragment, it will update the title on the Toolbar, but also it will add an up action on the toolbar. Now, this looks quite weird and initially, I thought that it is a bug. So I reported it as an issue, because, as of the Bottom Navigation Guidelines, navigating to another section in the BottomNavigationView and then clicking the system back button should not get the user back to the initial screen, but rather close the screen. So, navigating to a separate section should not add the new section to the stack, and clicking back pop it from the stack. But in my case, the result was unexpected: