Navigation Architecture: Android Jetpack (Part 2)

Nikhil Singh
Mobcoder LLC
Published in
9 min readAug 12, 2020

--

Hi Folks,

If you haven’t gone through the first part of this blog then, please you should first jump to there to clear the basics of what we are gonna do in this part2.

So, here is a link to visit part1 for the same.

In this part2, We will learn how to control all the fragments which have been added in the first part using the NavController, animation between these fragments while entering and exit and handling of the back stack, send the data from one screen to another screen.

Entering a destination
Exiting a destination
Entering a destination via a pop action, an action that pops additional destinations off of the back stack when navigating.
Exiting a destination via a pop action
“Entering” refers to the destination that is coming onto the screen, while

Let’s get started!!

In the last blog, I have been created six fragments namely as:

  1. MainFragment
  2. View Balance
  3. View Transactions
  4. Choose Recipient
  5. SpecifyAmount
  6. Confirmation

Navigate to a destination:

Navigating to a destination is done using a NavController, an object that manages app navigation within a NavHost. Each NavHost has its own corresponding NavController. You can retrieve a NavController by using one of the following methods:

Kotlin:

Fragment.findNavController()
View.findNavController()
Activity.findNavController(viewId: Int)

Java:

NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)

1. How to navigate using the NavController?

In the last post, I have been shown the navigation of all the screens. Means I connected all the screen using the navigation graph in the design tab.

So, Here am gonna show you how to navigate from one screen to another using the NavController. I am gonna show you the navigation control only with the main fragment rest is the same you can check my following Github link for this demo project source code.

So, Let’s see with the MainFragment. our Main fragment has three destination View Balance Fragment, View Transaction Fragment, and the last one is Choose Recipient fragment.

Use of NavController to navigate from one screen to another screen

So, Here we just created a navController object and retrieve it by using the view.findNavController in OnViewCreate. It gets the entire control of the fragment_main layout file. Which further helps to do the navigation between the fragments.

Next, we set the listener for the three-button that moves us to three different screens.

navController.navigate(R.id.action_mainFragment_to_viewTransactionFragment)

Here navigate(int destination_id) is used to reach the next screen or destination. In our case destination id is R.id.action_mainFragment_to_viewTransactionFragment.

Don’t appall here to see this long text id because it creates automatically after you linked the actions of the screens in the nav_graph design tab. So this long text id gives state forward meaning.

2. Animation Transaction between destination:

You can make an animation transaction between the source and destination using two ways:

  1. Using the Android default animation files
  2. Using your own created animation file (customizable)
  3. Using the Android default animation files:

Navigation also includes several default animations to get you started. To add animations to action, do the following:

  • In the Navigation editor, click on the action where the animation should occur.
  • In the Animations section of the Attributes panel, click the dropdown arrow next to the animation you’d like to add. You can choose between the following types:
    • Entering a destination
    • Exiting a destination
    • Entering a destination via a pop action, an action that pops additional destinations off of the back stack when navigating.
    • Exiting a destination via a pop action
    Choose an animation from the list of project animations that appears.
figure 1: The Animation section of the Attribute pannel

Once you’ve added animations, click the Text tab to toggle to the XML text view. The XML for the animations now appears in the corresponding <action> element. In the following example, specifyAmountFragment is the source destination for the confirmationAction action:

figure 2: Use of animation attributes to feel the destination transaction cool

Let’s Understand these four Animation attributes:

  1. Entering a destination
  2. Exiting a destination
  3. Entering a destination via a pop action, an action that pops additional destinations off of the back stack when navigating.
  4. Exiting a destination via a pop action

“Entering” refers to the destination that is coming onto the screen, while “exiting” refers to the destination leaving the screen.

Therefore when you navigate from destination A to destination B, the entering destination B will have the enterAnim applied to it and the exiting destination A will have the exitAnim applied to it.

When the user hits the system Back button, going from B back to A, the reverse happens: the entering destination A will have the popEnterAnim applied to it and the exiting destination B will have the popExitAnim applied to it.

2. Using your animation file (customizable):

You can create your animation files for showing this animation effect between the source and destination transaction.

For that, you will have to create an anim directory under the resource folder and create your custom animation file like below.

figure 3: anim folder with custom animation files

3. Handling of the Back-Stack in nav_graph:

Android maintains a back stack that contains the destinations you’ve visited. The first destination of your app is placed on the stack when the user opens the app. Each call to the navigate() method puts another destination on top of the stack. Tapping Up or Back calls the NavController.navigateUp() and NavController.popBackStack() methods, respectively, to remove (or pop) the top destination off of the stack.

NavController.popBackStack() returns a boolean indicating whether it successfully popped back to another destination. The most common case when this returns false is when you manually pop the start destination of your graph.

When the method returns false, NavController.getCurrentDestination() returns null. You are responsible for either navigating to a new destination or handling the pop by calling finish() on your Activity, as shown in the following example:

Use of popUpTo and popUpInclusive:

When navigating using an action, you can optionally pop additional destinations off of the back stack. For example, if your app has an initial login flow, once a user has logged in, you should pop all of the login-related destinations off of the back stack so that the Back button doesn’t take users back into the login flow.

To pop destinations when navigating from one destination to another, add an app:popUpTo attribute to the associated <action> element. app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate(). The attribute value is the ID of the most recent destination that should remain on the stack.

You can also include app:popUpToInclusive=” true” to indicate that the destination specified in the app:popUpTo should also be removed from the back stack.

Let’s say that your app has three destinations — A, B, and C — along with actions that lead from A to B, B to C, and C back to A. The corresponding navigation graph is shown in figure 4:

figure: 4 A circular navigation graph with three destinations: A, B, and C.

With each navigation action, a destination is added to the back stack. If you were to navigate repeatedly through this flow, your back stack would then contain multiple sets of each destination (A, B, C, A, B, C, A, and so on). To avoid this repetition, you can specify the app:popUpTo and app:popUpToInclusive in the action that takes you from destination C to destination A, as shown in the following example:

After reaching destination C, the back stack contains one instance of each destination (A, B, C). When navigating back to destination A, we also popUpTo A, which means that we remove B and C from the stack while navigating. With app:popUpToInclusive=” true”, we also pop that first A off of the stack, effectively clearing it. Notice here that if you don’t use the app:popUpToInclusive, your back stack would contain two instances of destination A.

4. Passing the data between destinations:

Navigation allows you to attach data to a navigation operation by defining arguments for a destination.

Define destination arguments:

To pass data between destinations, first define the argument by adding it to the destination that receives it by following these steps:

  • In the Navigation editor, click on the destination that receives the argument.
    • In the Attributes panel, click Add (+).
    • In the Add Argument Link window that appears, enter the argument name, argument type, whether the argument is nullable, and a default value, if needed.
    • Click Add. Notice that the argument now appears in the Arguments list in the Attributes panel.
    • Next, click on the corresponding action that takes you to this destination. In the Attributes panel, you should now see your newly added argument in the Argument Default Values section.
    • You can also see that the argument was added to XML. Click the Text tab to toggle to XML view, and notice that your argument was added to the destination that receives the argument. An example is shown below:

Use safe args to pass data with type safety:

The Navigation component has a Gradle plugin called Safe Args that generates simple object and builder classes for type-safe navigation and access to any associated arguments. Safe Args is strongly recommended for navigating and passing data because it ensures type-safety.

In some cases, for example, if you are not using Gradle, you can’t use the Safe Args plugin. In these cases, you can use Bundles to directly pass data.

To add Safe Args to your project, include the following classpath in your top-level build.gradle file:

To generate Java language code suitable for Java or mixed Java and Kotlin modules, add this line to your app or module’s build.gradle file:

Alternatively, to generate Kotlin code suitable for Kotlin-only modules add:

After enabling Safe Args, your generated code contains the following type-safe classes and methods for each action as well as with each sending and receiving destination.

A class is created for each destination where an action originates. The name of this class is the name of the originating destination, appended with the word “Directions”. For example, if the originating destination is a fragment that is named SpecifyAmountFragment, the generated class would be called SpecifyAmountFragmentDirections.

This class has a method for each action defined in the originating destination.

For each action used to pass the argument, an inner class is created whose name is based on the action. For example, if the action is called confirmationAction, the class is named ConfirmationAction. If your action contains arguments without a defaultValue, then you use the associated action class to set the value of the arguments.

A class is created for the receiving destination. The name of this class is the name of the destination, appended with the word “Args”. For example, if the destination fragment is named ConfirmationFragment, the generated class is called ConfirmationFragmentArgs. Use this class’s fromBundle() method to retrieve the arguments.

The following example shows you how to use these methods to set an argument and pass it to the navigate() method:

In your receiving destination’s code, use the by navArgs() method to retrieve the bundle and use its contents.

So, This is the way to pass the data using safe args However we can pass the data with Bundle without safe args.

Here is an example of passing the data from ChooseRecipientFragment to SpecifyAmountFragment.

And Here is How do we catch the data in SpecifyAmountFragment.

So, guys, we have done with the Navigation Architecture I tried to complete all the things from my side if there is something I left or If you got the better clarity about this Navigation Architecture after reading this blog.

Please drop your thoughts in the response section and I will reply to you for the same.

For the complete code, you can download or check from the GitHub link.

Thank you !!
Nikhil Singh (Android Developer)

--

--