Android Jetpack architecture component - detailed explanation of Navigation in the pit

Posted by BRAINDEATH on Wed, 11 Dec 2019 10:14:30 +0100

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.

Scan below the two-dimensional code to pay attention to the public number and get more dry goods.

Topics: Android Fragment xml Gradle