What's new in Navigation Component by example.
The last month, at Google I/O 2019, the Android Jetpack engineers presented to us the latest version of one of the most interesting components, the Navigation Component 2.1.0.
This version is still in alpha channel (precisely in alpha05) and that's why I’ve decided to play a little bit with it to be ready for the stable release. Let's see what's this all about.
What's Navigation Component?
The Navigation Component comes as part of the Android Jetpack, precisely as an Architecture Component. Basically, it completely changes the way we navigate through views in Android, simplifying it by reducing boilerplate and providing a simple API to navigate everywhere in your app regardless of where you currently are. Whatsmore, in most cases you won't have to worry about managing the stack, the back navigation and of course, all the problems related to committing fragments.
There are three important components in Navigation which will help us to achieve our navigation aims:
- Navigation Graph: This graph is where is set all the navigation configuration for a particular NavHost.
- NavHost: It's an empty container where navigation will take place. In other words, it is where views will be swapped in and out.
- NavController: This is the object which will handle all the navigation in our application.
Adding the dependencies
To start using Navigation we must add the dependencies to our project. It can be found in Google's Maven Repository.
I'm using the buildSrc module to build the project and that's why I've defined the dependencies like that.
Add to the app's gradle file:
This post is completely written for Kotlin users and the example in the repository is also in this beautiful language. But, if your entire project is still in Java (and you do not have any intentions of changing it) there is a Java version of the Navigation library that you can import instead.
Defining the Navigation Graph
The first thing you need to do after adding the dependencies is to set your navigation graph. As mentioned before, this graph is the place where you define all your navigation structure with its directions, actions, and arguments. It must be added in a navigation folder into the res folder.
Our example has two activities and a dialog (which is the new thing here, in the alpha channel) and several fragments. Let's take a look at it…
You can also create this file using the Android Studio tool for it but the result will be the same. This is how it looks like for our example application:
The interesting thing here is that we are able to see a preview of our views in the graph as we can appreciate in the previous image. This is very useful when we are designing our application due to it shows us a complete panoramic picture of the section we are working on.
If you haven't generated some view but you want to set a navigation action for designing purposes, you can use the blankFragment provided in the library.
The loginFragment has a little house icon associated with its name meaning that this is the start destination of the navigation graph. You can set and change this by selecting the fragment in the Android Studio and pressing the little house button in the upper menu or you can make it in the old way by setting the app:startDestination in the navigation tag of your graph.
Every navigation graph has a Navigation Host associated. In this case, the LoginActivity contains the login's navigation host. This navigation host is a fragment tag which you can constraint to any view like any other known view types (and customs) in Android. All the transitions will occur in there, no matter the space, no matter the final position of the host.
Let's pay special attention to the defaultNavHost value that we have set in true. This means that in case we have multiple navigation hosts in the same layout, this is the one which the system will use to handle the back action when navigates. One and just one of them can be set to true.
Once added several fragments to our graph, it's time to connect them. To achieve this we have actions. Actions allow us to define a destination to navigate in a very simple and concrete way. This is the action defined to navigate from our loginFragment to our recoveryPasswordFragment:
The action's id is what you are gonna use to tell the navigator that navigates to the destination defined below. Destination's id is a custom id that you have already set on the destination tag, into the navigation file. This action has to be contained into the fragment, activity or dialog from where you need to navigate from. You can set several actions over the same fragment to navigate different places and it's just that easy as it seems.
Navigate using the action defined
After defining your action in the navigation graph (a thing you can also aim by connecting both views through arrows using the Android Studio tool) and in order to perform the navigation itself, you need to set up your NavController.
You can obtain an instance of this object every time you need to use it or, knowing you will use it all around your fragment, you can get an instance after the view is created.
Now, to navigate to the recover password fragment, when the user clicks on the text button just use the instance of the NavController that we've already saved and call the navigate method with the id defined in the action.
We have talked about navigation between destinations but, what we haven't talked about yet is passing arguments (or extras if the destination is an Activity).
There are two different ways to pass data when navigates with Navigation Component. Let's see them.
As we all should know, to send data through activities and fragments (or vice versa) you must create a Bundle. Therefore, to send data to different destinations using Navigation Component you can use a Bundle too.
In your destination, whether it be a fragment or an activity, the loggedUser must be recovered as usual.
SafeArgs is a new way to pass data between destinations with a great advantage against traditional Bundle, type safety. Basically, it's a plugin that generates classes to pass and extract data between destinations.
To use it, add the plugin to your classpath:
and apply it to your app main module:
The plugin will generate classes for every destination in the project and will create typed factory methods to pass data through it. These classes have the view's name with the Directions suffix and the factory methods will be named as the action. Next, navigate using the destination object it creates instead of using the actionId. But, in order to generate these classes, the plugin needs that we specify the arguments in the destination we need to pass the data.
This argument must have a name and an argument type, the last of course, for the plugin to create the helpers. The argument type can be of several types, including Serializable and Parcelable. Full types can be checked here.
This is how navigates using safeArgs helpers classes:
And this is how you recover the data in the destination:
As you see, the plugin also generates classes to recover the data. These classes will be named as the destination plus the Args suffix.
If you are using ProGuard you must add rules to keep the Serializable, Parcelable and Enum used as arguments out of being modified. This can be achieved using the @Keep annotation or adding the rule in the ProGuard file.
Navigating to Dialogs
The current navigation version adds also the possibility to navigate to dialogs just as you do with fragments or activities, and from them to other directions. Just replace the fragment tag for a dialog tag, change the app:name attribute with the dialog full name and that's all.
DeepLinking has never been so easy as with the Navigation Component. You just need to specify the deeplink in your destination, add some code in manifest and that's all.
I'll be covering these topics in future application updates.
Navigation in Android applications is becoming a very easy task with Navigation Component. If you are planning to add it to your application I'll suggest starting from now. Just remember that you'll need to wait a little bit to use the navigation to dialogs in production code because it's still in the alpha channel.
I’ll be updating the application to cover more navigation cases and adding additional examples. All suggestions are welcome.
If you found this post useful, please support it with a 👏 .
Full Github repository can be found in the link above.