Navigation Controller - An Android Storyboard?

Ashwin S
AndroidPub
Published in
6 min readMay 13, 2018

Well, this was coming, wasn’t it? The time of the year when Google introduces developer features through it’s I/O with the primary emphasis on better code practice and reduced development burden to implement this best practice. One such feature is the Navigation Controller of the Android Architecture Components.

What if you were given a Storyboard which has a blueprint of the application’s logical flow much like in iOS? Well, join me as I continue my series on the Architecture Components with the Navigation Controller! 😃

Why Navigation?

  1. Fragment Transaction takes place asynchronously. Though it is generally a good thing, it might lead to a data race when another piece of code tries to read the state of the fragment. Aah, those painful IllegalStateExceptions!
  2. Guidelines state that Deep Linked screen on back pressed will have to lead back to their previous logical screen. And we have to handle that manually.
  3. Testing is much easier.
  4. Passing arguments is much safer (save from refractor hell!)

Should we write these Fragment Transactions by hand anymore? Should we put more effort for a well maintained deep link? Well not anymore if you become a fan of this particular Navigation.

Components of Navigation!

  1. Navigation Graph: Blueprint of the Navigation destinations and actions that link them.
  2. Destinations: List of all the fragments. We can specify arguments, actions and deep link URLs to these destinations.
Destinations

3. Host: The parent activity and entry point for your application logic.

4. Actions: Specifies the destination fragment, transitions to that fragment, arguments and pop behaviour.

Actions

Alright fellas time to get our hands dirty with the Navigation code. 😎

Prerequisites

  1. A basic knowledge of Android Architecture Components, which I have highlighted clearly in my previous blog.

2. Android Studio 3.2 Canary 14 for Navigation Editor and adding the Navigation file.

3. The following dependancies for Navigation.

dependencies {
def nav_version = "1.0.0-alpha01"
implementation "android.arch.navigation:navigation-fragment:$nav_version"
implementation "android.arch.navigation:navigation-ui:$nav_version"

}

I will be continuing the application I built for the Android Architecture Components demo by adding 3 fragments for welcome screen, query editor for the list and the list display.

Creating the navigation file

Right click on res folder to create an Android Resource file. Provide a name for your navigation file and Resource type as Navigation. A navigation file is created as,

Now the following window appears,

New Destination

Either create a new blank destination which gives you a prebuilt fragment pattern (again a suggested best practice to write a fragment for beginners) or you can add an existing fragment as destination. I will be going with the later.

By default the Start Destination should be the first destination you chose for navigation. Feel free to play with the startDestination attribute to start with a different fragment on activity start.

After adding the destinations, your navigation xml should look like this.

Configuring your activity layout

Add the following to your host activity xml.

Specify your Navigation xml in the navGraph attribute, specify the name to be “androidx.navigation.fragment.NavHostFragment” which will provide you a Navigation Controller to navigate to other destinations and defaultNavHost attribute to be true to let it handle back press and other life cycle events.

Navigate to a destination

To navigate to a destination, you can utilise one among the four methods,

Some of these methods did not work as expected in my case and so I resorted to this method,

NavHostFragment.findNavController(this).navigate(R.id.startFragment)

Here this is the instance of the current fragment and the id within navigate() call is the id of the destination fragment to navigate to.

Actions!

We resort to actions instead of the direct fragment id navigate for transition effects and pop behaviour definition. We use the <action> tag to define our action.

The popUpTo attribute defines the pop behaviour of the current fragment. It removes the fragments from the top of the stack until the id of the fragment which you have specified. This comes in handy when you want to navigate back to one of your earlier fragments instead of your immediate previous.

Well you can call the navigation to destination by using the id of the action as in the earlier case with the fragment id as,

NavHostFragment.findNavController(this).navigate(R.id.action_startFragment_to_listingFragment)

Now run your app and see how seamlessly your app transitions from one fragment destination to the other.

Setting up your Activity UI components with the NavController

The NavigationUI class provides these rich set of methods to set your activity UI up with the Navigation Controller. This offers a two way sync of navigating between fragments using this UI components as well as updating your UI elements with which you just navigated. Here’s a sample.

Source from Google I/O

This blog would be incomplete without covering the wonderful add-ons which comes along with the Navigation Controller.

Type Safe Arguments

A safe recommended way of passing values from one fragment to the other. Here are the specific requisites.

In project-level dependancies add,

dependencies {
classpath 'com.android.tools.build:gradle:3.2.0-alpha14'
classpath 'android.arch.navigation:navigation-safe-args-gradle- plugin:1.0.0-alpha01'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

And include it as the following plugin under the other existing plugins in app level build.gradle,

apply plugin: 'androidx.navigation.safeargs'

You can add your <argument> tag for the destination fragment as follows,

The plugin helps you generate a directions class for the Source Fragment and use it to add the arguments to pass to the destination. We navigate to the destination with the directions object.

We consume the arguments with the help of Args class generated by the plugin for the Destination fragment.

Deep links

We can provide Explicit Deep Links for our destinations from application widget or notification with the help of a Pending Intent as follows,

PendingIntent deeplink = Navigation.findNavController(v).createDeepLink()
.setDestination(R.id.android)
.setArguments(args)
.createPendingIntent();

We can also provide Implicit Deep Links to redirect a URL to a particular destination of our app with the help of <deepLink> tag as,

We can obtain the parameter of the URL from the Destination Fragment’s arguments!

arguments?.getString("myarg")

Here are the other supported patterns for URL Deep links.

Source from Google I/O

Be sure to include the <nav-graph> tag for implicit Deep linking to work.

Well folks, we have come to the end of this long coaster ride. I hope this blog would give you a basic idea of how to get started with the Navigation Controller of the Android Architecture Components. Do check out my updated Android Architecture Demo project. 😊

Happy Reading people!

This blog is heavily inspired by the Google I/O 2018 talk on “Android Jetpack: manage UI navigation with Navigation Controller (Google I/O ‘18)

--

--