As Android Developer you may have heard of Android Navigation Components which has been announced in Google I/O 2018. This library has just reached a stable version in March 2019. Therefore, this might be a good time to start trying it out. The current Application that I’ve been working on is utilizing a Single-Activity Architecture as well as Architecture Component ViewModel and LiveData. In this article, I would like to demonstrate how to handle complex application flow using the Android Navigation Components.

Before we begin, I’ll assume that you have some basic knowledge of Android Navigation Component. Here are some articles that might be able to get you to start.

If you have somemore time taking Google Code Lab is a good idea.

Let’s kick off with the real situation that I’ve faced 😀

Let’s say that you have to create an app that has an authentication system then after the users go through a set of authentication-related screens and successfully log in to the application, they will be navigated to different flow base on their user type. Please refer to the picture below for a more precise explanation.

Without Navigation Component, we would have to create a bunch of Activities that might be with or without Fragments. At this point, you might have a question.

Is Single Activity really enough?

The first question coming into my mind when I started using this library is “Is having one activity like the recommended single-activity architecture is really enough for handling a complex application flow?”. Eventually, I realized that the key to solving the complicated flow with only one Activity is the way we define a navigation graph.

A navigation graph is a resource file that contains your destinations and actions. The graph represents your app’s navigation paths.

Defining nested navigation graphs is the key to handle a complex navigation flow with only on Activity.

Defining a navigation graph

It may be obvious to some of you on how to define navigation graph of this flow. However, I was not that smart. I used to break the single-activity architecture and put each flow(authentication, flow1, flow2) into different activities. I ended up with the code that wasn’t looked so beautiful. Later on, I came up with a more elegant method which fit the single-activity architecture. I utilized the nested navigation graph. I created the main navigation graph for the main flow and let each sub-flows have their own navigation graph like the figure below.

There are totally four navigation graphs. In our one and only Activity, we have NavHostFragment set up with @navigation/main_navigation which will be our main graph. Then other three fragments in @navigation/main_navigation will have thier own NavHostFragment with different navigation graph set up. Our @navigation/main_navigation graph will look similar to this.

I will skip the implementation of navigation graph of authenticationFragment, flow1Fragment, and flow2Fragment.

Navigating Inside and Between graph

Navigating to a destination is done using an element called NavController. Each NavHostFragment with a navigation graph has its own corresponding NavController for managing the navigation. For our example, the NavController would be attached to Activities or Fragments. I will give them the names like this.

As you can see that there’re four NavController in our example.

At the Activity level, we have mainNavController for navigating across each flow. At the fragment level, there are authenticationNavController, flow1NavController, and flow2NavController for controlling the navigation of each specific application flow.

I’ll bring up another example to explain how we can navigate inside the navigation graph that the screen belong to as well as the way to navigate between different navigation graphs. Suppose we have a login screen that belongs to the authentication navigation graph. It looks like this

This screen should be able to navigate to other authentication-related screens in the same flow such as ForgotPasswordScreen, RegistrationScreen, and such. However, it should also be able to navigate to the Flow1 or Flow2 after the user has successfully logged in. Please see the picture below for visual presentation.

To make the navigation according to what I’ve mentioned possible, we need to have an instance of both authenticationNavController and mainNavController, and this is where I see the benefit of using a Single-Activity architecture.

Please see a snippet of LoginFragment below.

As you can see that in LoginFragment, we have created authenticationNavController and mainNavController.

- mainNavController can be obtained by an instance of the Activity and it used to navigate to fragment outside of the @navigation/authentication_navigation. In this case, it’s to navigate to Flow1Fragment and Flow2Fragment

- authenticationNavController is achieved by an instance of the current view of the Fragment. It helps navigate to the screen inside @navigation/authentication_navigation.

The benefit of using a Single-Activity Architecture is that no matter which Fragment you are on or how deep the nested Fragment you are working with. It shares the same activity which means you can always create the instance of mainNavController and use it to navigate across the flows.

Conclusion

By using the concept that I’ve mentioned, it should cover some of the complicate navigation scenarios that we might have faced.

Fragments can have access to both the view-level NavController and the activity-level NavController. In the case of nested Fragment, it doesn’t have to care about what outer-level Fragment navigations are. It only needs to work with its own NavController.

That’s it for this article. Thank you for reading this. If you feel like my approach is not correct or have better implementations, please do suggest in the comment section. I would love to have a discussion. Plus, feel free to leave questions.

Please feel free to hit the claps and follow me. 😀