Navigation Component, Designing Navigation graph

Karishma Agrawal
HealthifyMe Tech
Published in
5 min readSep 9, 2020

In this blog, I would like to bring to you Nested graph and a discussion on how to pass data between two destinations.

Nested Navigation graph

A navigation graph can be used to group a series of destinations together and reuse them. For example, you use a view that can be used at multiple places in your application. So, you create a separate layout file and just include that wherever you want to reuse it. The same goes for the nav graph. A common flow can be included at multiple places by separating it in a diff XML file.

Explaining with an example: The Custom Meal

The feature of the Custom Meal in the Healthify app would help the user create meal combos. If a user likes fruits and toast for breakfast, he doesn’t have to add both, each and every day. He could create a combo meal of these two items and check the specific combo. This is a huge plus in time-saving.

Custom meal flow @eyepoppper

Shown above is the Custom meal flow; the user can name his meal and add the items in his meal to create the combo. If the simple dish is not available, he can add the ingredients.

The add button would take the user to a search screen and the searched food can be added in the list, and finally, store it by clicking on the save button, and the user will see a success screen and then we move back to the screen from where this flow started.

Let’s create a Navigation graph for Create combo flow.

<!-- create_meal_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/create_meal_graph"
app:startDestination="@id/createMealFragment">
<fragment
android:id="@+id/createMealFragment"
android:name="com.example.healthify.CreateMealFragment"
android:label="fragment_create_meal"
tools:layout="@layout/fragment_create_meal" >
<action
android:id="@+id/action_createMealFragment_to_save"
app:destination="@id/processMealFragment" />
<action
android:id="@+id/action_createMealFragment_to_add"
app:destination="@id/searchFoodFragment" />
</fragment>
<fragment
android:id="@+id/searchFoodFragment"
android:name="com.example.healthify.SearchFoodFragment"
android:label="search_food"
tools:layout="@layout/fragment_search_food"/>

<fragment
android:id="@+id/processMealFragment"
android:name="com.example.healthify.ProcessMealFragment"
android:label="done"
tools:layout="@layout/fragment_process_meal"/>
</navigation>

So here we have CreateMealFragment with 2 actions:

  1. action_createMealFragment_to_save -> when the user clicks on save after entering meal name and ingredients, he will move toProcessMealFragment So destination for that action is processMealFragment .
  2. action_createMealFragment_to_add -> When the user clicks on the plus icon to add more ingredients in the combo we move to the search screen where you can search for food and add it, so the destination for this action is searchFoodFragment .

This flow has 3 diff hooks.

Create meal hooks Shivangi Chowdhry

A User can enter into this flow by clicking the CREATE COMBO button on the meal tracker screen (fig 1) or CREATE A COMBO button from the Meal combo screen(fig 2) or the ADD FOOD button in the search flow(fig 3).

HOOK 1: Meal tracker screen

<!-- meal_tracker_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/meal_tracker_graph"
app:startDestination="@id/mealTrackerFragment">
<include app:graph="@navigation/create_meal_graph" /><fragment
android:id="@+id/mealTrackerFragment"
android:name="com.example.healthify.MealTrackerFragment"
android:label="MealTrackerFragment"
tools:layout="@layout/fragment_meal_tracker">
<action
android:id="@+id/action_merge_flow"
app:destination="@id/create_meal_graph" />
</fragment>
...
</navigation>

Here we have MealTrackerFragment and we have included create a meal graph. On click of CREATE COMBO button user will enter in create meal flow.

button.setOnClickListener{
Navigation.findNavController(view).navigate(R.id.action_merge_flow)
}

HOOK 2: Meal combo screen

<!-- my_meal_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/my_meal_graph"
app:startDestination="@id/myMealFragment">
<include app:graph="@navigation/create_meal_graph" /><fragment
android:id="@+id/myMealFragment"
android:name="com.example.healthify.MyMealFragment"
android:label="MyMealFragment"
tools:layout="@layout/fragment_my_meal">
<action
android:id="@+id/action_create_meal"
app:destination="@id/create_meal_graph" />
</fragment>
...
</navigation>

Here we have MyMealFragment and we have included create_meal_graph . On click of CREATE A COMBO button user will enter in create meal flow.

button.setOnClickListener{
Navigation.findNavController(view).navigate(R.id.action_create_meal)
}

Hook 3: Search flow, here we will understand nested graph as well as how to pass data between two destinations

Navigation allows you to attach data to a navigation operation by defining arguments for a destination. For example, in this case, we can pass meal Type(Breakfast, Lunch, dinner) as an argument in Create meal Fragment.

In general, you should strongly prefer passing only the minimal amount of data between destinations. For example, you should pass a key to retrieve an object rather than passing the object itself, as the total space for all saved states is limited on Android. If you need to pass large amounts of data, consider using a ViewModel .

To pass data you need to define an argument in the destination fragment where you want to receive data.

In this example, we are sending meal type from 3 diff hooks, and it will be received by CreateMealFragment. SO we need to define arg in CreateMealFragment.

<fragment
android:id="@+id/createMealFragment"
android:name="com.example.healthify.CreateMealFragment"
android:label="fragment_create_meal"
tools:layout="@layout/fragment_create_meal" >
<argument
android:name="mealType"
app:argType="string"
android:defaultValue="" />
</fragment>

If an argument type supports null values, you can declare a default value of null by using android:defaultValue="@null".

You can check all supported argument types from HERE.

We can pass arguments through “Deeplink” too.

<deepLink
android:id="@+id/deepLink"
app:uri="www.example.com/createMealFragment/{mealType}"
android:autoVerify="true"/>

From the sender fragment create a bundle of argument and pass it to nav controller.

<!-- search_meal_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/search_meal_graph"
app:startDestination="@id/searchMealFragment">
<include app:graph="@navigation/create_meal_graph" /><fragment
android:id="@+id/searchMealFragment"
android:name="com.example.healthify.SearchMealFragment"
android:label="SearchMealFragment"
tools:layout="@layout/fragment_search_meal">
<action
android:id="@+id/action_add_meal"
app:destination="@id/create_meal_graph" />
</fragment>
...
</navigation>
<!--searchMealFragment.kt -->
companion object {
const val MEAL_TYPE = "mealType"
// this value should be same as argument name in nav graph
}
val bundle = bundleOf(MEAL_TYPE to "Breakfast")
findNavController().navigate(R.id.action_add_meal,bundle)

This was a small discussion on nested graphs, how to use a nav graph, and how to pass data between two destinations.

I hope the article was informative for you. If you have any feedback or query please write back to me.

Till Happy Learning!

--

--

Karishma Agrawal
HealthifyMe Tech

Android Developer @Eventbrite | Wanted to be a writer so I write code now | Reader