This is the second MAD Skills series about navigation. This article is the third article in the navigation component series. If you want to review the content published in the past, please refer to the link below to view:
- Overview of navigation components
- Navigate to the dialog
- Use SafeArgs when navigating in the app
- Use deep link navigation
- build your first app bundle
- NavigationUI
- Use navigation component: Conditional navigation
If you prefer to watch video rather than reading the article, please click here to view video content.
Overview
In the previous articles in this series, we added the coffee record function, used the navigation UI to improve the user experience, and implemented conditional navigation.
In this article, we will learn how to manage navigation graphs by using nested graphs, and use the include tag to introduce other graphs. This requires us to modularize the application and understand how navigation is implemented between modules.
So, next, let us open Android Studio and start learning how to use navigation on the module.
Nested Navigation Map
We start with the navigation map. Nested graphs allow you to group a series of destination pages in the parent navigation graph.
Let's take a look at the navigation map. The coffeeList and coffeeEntryDialog destination pages are very suitable for conversion to nested maps. To achieve this, I long press shift and select "Move to Nested Graph" at the same time:
△ Move coffeeList and coffeeEntryDialogFragment to nested graph
Now we return to the code interface, you can see that the nested graph is just a new navigation graph in the root graph:
<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>
The navigation between the selected fragments is migrated to the nested graph.
Nested graphs must contain id. You can use this id to implement the code that navigates to the nested graph, but it is not directly converted to its sub-destination page. Nested graphs contain their own start destination pages, and please do not expose their sub-destination pages separately.
<navigation
android:id="@+id/coffeeGraph"
app:startDestination="@id/coffeeList">
If you double-click the nested graph, you can find the nested destination pages and the operations between them.
Include Tag
In addition to using nested graphs, I can also extract graphs into a new navigation xml file. I created a new xml file here, named coffee_graph, and migrated the content 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>
I can nest the new graph into other files through the include tag. Although using the include tag is functionally the same as using nested diagrams, you can also use diagrams from other project modules or library projects.
<include app:graph="@navigation/coffee_graph"/>
Similar to the nested graph, the referenced graph 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" />
Here I updated the menu to use the id of the reference image. Since CoffeeList is the starting page of the referenced graph, I can use the graph id to navigate to this graph. If you try to run the application now, all functions will be the same as before.
Now that the navigation map of the coffee record has been separated, we can modularize the application. By the way, we can see how the navigation between modules is effective.
If you want to operate synchronously, you can check the code , which contains all the changes I have made so far. I created two new modules: core and coffee. I migrated all the commonly used classes to 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 coffee records to the coffee module. The layout and other resources used in coffee records are also migrated here, including coffee_graph.
△ Existing classes and resources have been migrated to core and coffee modules
The coffee module depends on the core module:
dependencies {
implementation project(":core")
//...
}
Finally, in the app module, add coffee and core as dependencies of the app module:
dependencies {
implementation project(":coffee")
implementation project(":core")
//..
}
Please note that there is no change in the navigation chart here, and it is not affected by these changes:
△ The navigation map has not changed
Now if you run the application, all functions are the same as usual, except that the module is used internally. You can view final code .
Through the above modification, I separated the coffee recording module and its related navigation flow from the application, which means that the coffee recording module can be used independently of the doughnut recording application.
summary
In this article, we learned how to create a nested navigation map and how to use the include tag to modularize the donut recording application.
In the next article, we will further learn how to use functional modules for navigation. stay tuned!
Welcome to Click here to submit feedback to us, or share your favorite content or problems found. Your feedback is very important to us, thank you for your support!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。