This is the second MAD Skills series on Navigation. This is the third article in the series on Navigation components. If you want to review past posts, please refer to the links below:
- Overview of navigation components
- Navigate to the dialog box
- Use SafeArgs when navigating your application
- Use deep links to navigate
- Build your first App Bundle
- NavigationUI is easy to understand
- Use navigation components: Conditional navigation
If you prefer to watch the video rather than read the article, check out the video here.
An overview of the
In previous articles in this series, we added coffee logging, improved the user experience with a navigation UI, and implemented conditional navigation.
In this article, we’ll learn how to manage navigation diagrams by using nested diagrams and introduce other diagrams using include tags. This requires modularity of the application and an understanding of how navigation operates between modules.
So, let’s open Android Studio and learn how to use navigation on modules.
Nested navigation diagrams
Let’s start with the navigation chart. Nested diagrams allow you to group a series of destination pages in a parent navigation diagram.
Taking a look at the navigation diagram, the coffeeList and coffeeEntryDialog destination pages are ideal for converting to nested diagrams. To do this, I long shift here and select “Move to Nested Graph” at the same time:
Delta will coffeeList and coffeeEntryDialogFragment moved to the embedded code
Now back to the code interface, you can see that the nested diagram is just a new navigation diagram in the root diagram:
<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"
app:startDestination="@id/donutList">
<fragment
android:id="@+id/donutList"
android:name="com.android.samples.donuttracker.donut.DonutList"
android:label="@string/donut_list" >
<action
android:id="@+id/action_donutList_to_donutEntryDialogFragment"
app:destination="@id/donutEntryDialogFragment" />
<action
android:id="@+id/action_donutList_to_selectionFragment"
app:destination="@id/selectionFragment" />
</fragment>
<dialog
android:id="@+id/donutEntryDialogFragment"
android:name="com.android.samples.donuttracker.donut.DonutEntryDialogFragment"
android:label="DonutEntryDialogFragment">
<deepLink app:uri="myapp://navdonutcreator.com/donutcreator" />
<argument
android:name="itemId"
app:argType="long"
android:defaultValue="-1L" />
</dialog>
<fragment
android:id="@+id/selectionFragment"
android:name="com.android.samples.donuttracker.setup.SelectionFragment"
android:label="@string/settings"
tools:layout="@layout/fragment_selection" >
<action
android:id="@+id/action_selectionFragment_to_donutList"
app:destination="@id/donutList" />
</fragment>
<navigation
android:id="@+id/coffeeGraph"
app:startDestination="@id/coffeeList">
<fragment
android:id="@+id/coffeeList"
android:name="com.android.samples.donuttracker.coffee.CoffeeList"
android:label="@string/coffee_list">
<action
android:id="@+id/action_coffeeList_to_coffeeEntryDialogFragment"
app:destination="@id/coffeeEntryDialogFragment" />
</fragment>
<dialog
android:id="@+id/coffeeEntryDialogFragment"
android:name="com.android.samples.donuttracker.coffee.CoffeeEntryDialogFragment"
android:label="CoffeeEntryDialogFragment">
<argument
android:name="itemId"
android:defaultValue="-1L"
app:argType="long" />
</dialog>
</navigation>
</navigation>
Copy the code
Navigation between selected fragments is migrated to nested diagrams.
Nested diagrams must contain ids. You can use this ID to implement code that navigates to the nested graph, but not directly to the subdestination page. Nested diagrams contain their own launch destination pages, and do not expose their child destination pages separately.
<navigation
android:id="@+id/coffeeGraph"
app:startDestination="@id/coffeeList">
Copy the code
If you double-click the nesting diagram, you can find the nested destination pages and the actions between them.
The Include tag
In addition to using nested diagrams, I can also extract diagrams into a new navigation XML file. I created a new XML file here, called coffee_graph, and migrated the contents of the nested graph to this file.
<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/coffeeGraph" app:startDestination="@id/coffeeList"> <fragment android:id="@+id/coffeeList" android:name="com.android.samples.donuttracker.coffee.CoffeeList" android:label="@string/coffee_list"> <action android:id="@+id/action_coffeeList_to_coffeeEntryDialogFragment" app:destination="@id/coffeeEntryDialogFragment" /> </fragment> <dialog android:id="@+id/coffeeEntryDialogFragment" android:name="com.android.samples.donuttracker.coffee.CoffeeEntryDialogFragment" android:label="CoffeeEntryDialogFragment"> <argument android:name="itemId" android:defaultValue="-1L" app:argType="long" /> </dialog> </navigation>Copy the code
I can use the include tag to nest new diagrams into other files. Although using the include tag is functionally the same as using nested diagrams, you can also use diagrams for other project modules or library projects.
<include app:graph="@navigation/coffee_graph"/>
Copy the code
Similar to nested diagrams, the referenced diagram does not expose the list of destination pages, which means I need to update the menu ID to point to the coffeeList.
<item
android:id="@id/coffeeGraph"
android:icon="@drawable/coffee_cup"
android:title="@string/coffee_name" />
Copy the code
Here I updated the menu to use the id of the reference graph. Since CoffeeList is the starting page of the referenced graph, I can use the graph ID to navigate to the graph. If you try to run the application now, all functions will be the same as before.
Now that the coffee record navigation diagram has been separated, we can modularize the application to see how well we navigate between modules.
If you want to synchronize operations, check out the code, which contains all the changes I’ve made so far. I created two new modules: Core and coffee. I migrated all the common classes into the Core module, such as Donut, Coffee, DAO, Database, and other common resources.
Next, I migrated all the Fragment, viewModel, and Adapter classes used in the coffee record into the coffee module. Layouts and other resources used in the coffee record are also migrated here, including coffee_graph.
Existing classes and resources are moved to core and Coffee modules
Coffee module relies on core module:
dependencies {
implementation project(":core")
//...
}
Copy the code
Finally, in the APP module, add coffee and core as dependencies of the APP module:
dependencies {
implementation project(":coffee")
implementation project(":core")
//..
}
Copy the code
Note that nothing has changed in the navigation diagram here, which is not affected by these modifications:
The navigation chart has not changed
Now, if you run the application, all the functions are the same as usual, but you use modules internally. You can view the final code.
With these changes, I have separated the coffee recording module and its associated navigation flow from the application, which means that the coffee recording module can be used independently of the donut recording application.
conclusion
In this article, you learned how to create nested navigation diagrams and how to use the include tag to modularize the donut recording application.
In the next article, we’ll take a closer look at how to navigate using functional modules. Stay tuned!
Please click here to submit your feedback to us, or share your favorite content or questions. Your feedback is very important to us, thank you for your support!