This article starts with WeChat public's "Android development tour". Welcome to pay more attention to get more dry goods.
Preface
Navigation is a direct translation of navigation, which is one of Android Jetpack components, making single Activity application the preferred architecture. The jump of Fragment page in the application is handled by navigation, so the developer does not need to deal with the complexity of Fragment transaction and related transition animation.
Specific use
Add dependency in gradle.build of app:
def nav_version = "2.1.0" implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
First, we define three fragments: Fragment1, Fragment2 and Fragment3. The implementation logic is that Fragment1 Click to jump to Fragment2, Fragment2 Click to jump to Fragment3, Fragment3 jump to Fragment1 and return to Fragment1 when clicking the return key.
navigation: the root of the navigation view XML. It defines the jump logic of related fragment s.
First, you need to create a new navigation folder under the resources directory, right-click to create a new Navigation resource file named NAV? Graph? Main.xml.
The lower left foot of the file is divided into two tabs: Design and Text. The Design view is visual, and relevant fragment s can be selected directly. The Text view is our handwriting related configuration.
Let's look at the NAV graph main.xml file defined below:
<?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" app:startDestination="@id/fragment1"> <fragment android:id="@+id/fragment1" android:name="com.jetpack.jetpackdemo.navigation.fragment.Fragment1" android:label="Fragment1" tools:layout="@layout/fragment1_layout"> <action android:id="@+id/fragment1_action" app:destination="@+id/fragment2" /> </fragment> <fragment android:id="@+id/fragment2" android:name="com.jetpack.jetpackdemo.navigation.fragment.Fragment2" android:label="Fragment2" tools:layout="@layout/fragment2_layout"> <action android:id="@+id/fragment2_action" app:destination="@+id/fragment3" /> </fragment> <fragment android:id="@+id/fragment3" android:name="com.jetpack.jetpackdemo.navigation.fragment.Fragment3" android:label="Fragment3" tools:layout="@layout/fragment3_layout"> <action android:id="@+id/fragment3_action" app:popUpTo="@id/fragment1" /> </fragment> </navigation>
There is a startDestination field in the navigation root node, which indicates which page is displayed by default. Define the related pages to route through the fragment tag. id is the unique identification of fragment. Name is the package name, which must be correct. Layout is the layout file of fragment, which is easy to view in Design view after configuration.
Child node action is configured in fragment. Action represents the specific behavior to be routed. Similarly, the id is also its unique identification. The destination represents the destination, that is, it needs to be routed to a specific page. popUpTo means pop up to a page. There are other properties of action, such as configuring animation. See Demo for details.
NavHostFragment is the display container of Navigation view,
<fragment android:id="@+id/nav_host_fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="0dp" android:layout_height="0dp" app:defaultNavHost="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/nav_graph_main" />
name is a fixed writing method, which must be specified as
androidx.navigation.fragment.NavHostFragment
The defaultNavHost field indicates whether to block the return key operation.
If true, the onSupportNavigateUp method is overridden in the required Activity.
Because by default, the return key does not go back to the fragment page.
override fun onSupportNavigateUp(): Boolean { return findNavController(R.id.nav_host_fragment).navigateUp() }
The navGraph field is our configured navigation view.
NavController
Get NavController through findNavController, and route between pages through navigator or navigate up of controller.
Then the logic of clicking the button on three pages is to challenge the corresponding page:
mBtn.setOnClickListener { Navigation.findNavController(it).navigate(R.id.fragment1_action) }
Tell Navigation the logic of jump by specifying the id of the action. The same is true for other pages.
Final effect:
Let's summarize the relationship among navigation, NavHostFragment, and NavController.
navigation is to plan a lot of routes, which need to be displayed in NavHostFragment. After the demonstration, how to take so many routes is up to NavController, just like the steering wheel, which route to take.
Transfer parameters
In the previous section, we explained the knowledge related to navigation, including a sub tag: argument. Is used to define parameters. For example, we add the argument tag to the fragment 2 tag as follows:
<argument android:name="name" android:defaultValue="navigation Navigation" app:argType="string" app:nullable="false" />
So when fragment1 jumps to fragment2, you can carry parameters. Where name is the parameter name. defaultValue is the default value. argType is the type of the parameter. nullable indicates whether it can be empty.
There are two ways to pass parameters between fragment s:
- Traditional Bundle approach
- safeArgs provided by Google
Traditional Bundle approach
Use Bundle to set and get parameters.
Set in fragment1:
mBtn.setOnClickListener { //If you want to use the default value of argument in xml, just pass in new Bundle() val args = Bundle() args.putString("name","adopt bundle Transfer parameters") Navigation.findNavController(it).navigate(R.id.fragment1_action, args) }
Get parameters in fragment2:
val args = arguments val name = args?.getString("name") mTvName.text = name
This allows the parameters to be passed. Do you think there is any problem in the above way?
Parameter name "name" is filled in manually in three places. This can easily lead to spelling mistakes and omissions when making changes. Very unfriendly. So Google gave us a plug-in: safeArgs. Let's take a look at the specific use.
safeArgs
First, you need to configure it. Add classpath configuration in build.gradle of the project:
dependencies { classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0' }
Then add the application plugin in build.gradle of app.
apply plugin: 'androidx.navigation.safeargs'
After the project is rebuilt, you will know to generate files with suffix of Directions for fragment. And automatically generate files with Args suffix for fragments with argument tag in navigation.
Set the parameters through the file with the suffix of Directions. The file with the suffix Args is used to get the parameters.
Set in fragment1:
mBtn.setOnClickListener { val args = Fragment1Directions.fragment1Action().setName("adopt safeArgs Pass parameters") Navigation.findNavController(it).navigate(R.id.fragment1_action, args.arguments) }
Get in fragment2:
val name = Fragment2Args.fromBundle(arguments!!).name mTvName.text = name
This completes the transfer of parameters between fragment s. The logic of setting parameters manually is completely avoided. Parameters are operated directly through setter and getter.
summary
In general, the use of Navigation is not complicated. It makes our single Activity architecture possible, and we do not need to care about the jump logic of specific fragment s. But there are also problems. Through source code analysis, we know that
FrameLayout is created in onCreateView of NavHostFragment, that is to say, the real container is FrameLayout. Instead of show and hide, the replace ment API is used internally when creating the fragment navigator. This causes the fragment to re execute every time in its lifecycle. So it's better to use it with ViewModel.