Codelabs-Jetpack Navigation

Reference: Official documentation

Welcome to point out any mistakes

My understanding of Navigation

  • forFragment: Do not operatesupportFragmentManager, which means yesreplace,show,hideBye-bye.
  • forActivity: It is likely to decrease substantiallyActivity, reduce usestartActivitybecausefragmentMore detailed life cycle, more convenient parameter transfer.
  • usedeepLinkThe deep chain jump is more convenient.

Three key components

Navigation graph

An XML resource file with the directory res/navigation/*.xml that configures the navigation content for navigation. Also known as route configuration.

Resource properties

<?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/sample_navigation"
    app:startDestination="@id/home_dest">

    <fragment
        android:id="@+id/home_dest"
        android:name="com.cxl.jetpack.nav.HomeFragment"
        tools:layout="@layout/home_dest"
        android:label="HomeFragment" >
        <action
            android:id="@+id/open_one_action"
            app:destination="@id/one_dest"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right"
            />
    </fragment>
    <fragment
        android:id="@+id/one_dest"
        android:name="com.cxl.jetpack.nav.OneFragment"
        android:label="OneFragment" >
        <argument
            android:name="flowStepNumber"
            app:argType="integer"
            android:defaultValue="1"/>
    </fragment>
</navigation>
Copy the code
  • tools:layout: Preview property. If this property is not configured, the preview will not be visible in the Design panel.
  • actionIt’s an action. It’s an actionfragmentTo switch between.
  • destination: destination, the jump destination.
  • enterAnim,exitAnim,popEnterAnim,popExitAnim: is the page switch and popover animation
  • argument: Similar to the Activity jump parameter transfer, but the parameter transfer is more convenient and simple, as follows:
    // Pass a value and jump
    val flowStepNumberArg=1
    val action = HomeFragmentDirections.nextAction(flowStepNumberArg)
    findNavController().navigate(action)
    / / value
    val safeArgs: FlowStepFragmentArgs by navArgs()
    val flowStepNumber = safeArgs.flowStepNumber
    Copy the code

You can also use the Design panel (can refer to this article: https://developer.android.com/guide/navigation/navigation-getting-started#nav-editor), it is more convenient.

NavHost

A host is used on the fragment layout as follows:

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.Toolbar
       . />

    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/sample_navigation" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        . />

</LinearLayout>
Copy the code

Can see much more than the average fragment layout three attributes of the android: name = “androidx. Navigation. Fragments. NavHostFragment”, the app: defaultNavHost = “true”, the app: navGra Ph = “@ navigation/sample_navigation”.

  • android:name: point toNavHostThe implementation of the classNavHostFragment.
  • app:defaultNavHost: The default value isfalse, when the value isfalseThe Fragment in the current Activity is usedNavigationAnd the use ofNavigationJump to the next oneFragmentNext oneFragmentClicking the Back key will exit the current pageActivity. fortrueIt’s time to go back to the last oneFragmentMiddle, if the last oneFragmentfornullWill exit the currentActivity. Similar to how we handle the WebView’s back event.
  • app:navGraph: point toNavigation graphThe configuration file

NavController

Can be understood as a route jump controller, which coordinates the exchange of target content in NavHost. As follows:

// No parameter to jump
findNavController().navigate(R.id.flow_step_one_dest, null, options)
// Or carry parameters
val flowStepNumberArg=1
val action = HomeFragmentDirections.nextAction(flowStepNumberArg)
findNavController().navigate(action)
Copy the code

So how do you use it

The first step is importing the dependency

Add the following code to build.gradle in your App directory:

.dependencies{...//Navigation
    implementation "Androidx. Navigation: navigation - fragments - KTX: 2.1.0." "
    implementation "Androidx. Navigation: navigation - UI - KTX: 2.1.0." "
}
Copy the code

It’s best to use the latest version, which can be found here (check the web if you can’t open it) :Google’s Maven Repository

Optional * : Add the following code to your project-level build.gradle:

...dependencies{...classpath "Androidx. Navigation: navigation - safe - the args - gradle - plugin: 2.1.0." "
    }
Copy the code

Build. Gradle = build. Gradle = build.gradle = build.

buildscript{
   ext{
        navigationVersion = "2.0.0"}}Copy the code

The above dependencies can be modified as:

// Item-level dependencies
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
/ / App level dependencies
implementation "androidx.navigation:navigation-fragment-ktx:$rootProject.navigationVersion"
implementation "androidx.navigation:navigation-ui-ktx:$rootProject.navigationVersion"
Copy the code

The second step is to build the basic framework

Create a few fragments and implement a layout like this:

Deep_link_dest.xml (corresponding to DeepLinkFragment)

<?xml version="1.0" encoding="utf-8"? >
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    android:textSize="80sp"
    android:text="Deep Link"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:ignore="HardcodedText"/>
Copy the code

Flow_step_one_dest.xml (corresponding to OneFragment)

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    tools:ignore="HardcodedText"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:textSize="68sp"
        android:text="1"
        android:layout_marginBottom="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <Button
        android:text="open 2"
        android:layout_width="200dp"
        android:layout_height="wrap_content"/>

</LinearLayout>
Copy the code

Flow_step_two_dest.xml (corresponding to TwoFragment)

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    tools:ignore="HardcodedText"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/twoTxt"
        android:textSize="68sp"
        android:text="2"
        android:layout_marginBottom="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:text="Finish Flow"
        android:layout_width="200dp"
        android:layout_height="wrap_content"/>

</LinearLayout>
Copy the code

Home_dest.xml (corresponding to HomeFragment)

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:gravity="center"
    tools:context="com.cxl.jetpack.nav.HomeFragment"
    tools:ignore="HardcodedText"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:textSize="68sp"
        android:text="HOME"
        android:layout_marginBottom="50dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/open1"
        android:text="open 1"
        android:layout_width="200dp"
        android:layout_height="wrap_content"/>

</LinearLayout>
Copy the code

Create a New Navigation Graph resource file

  • Click on the res folder, right-click on the menu and choose New->Android Resource File
  • Enter File name and select Resource Type as Navigation
  • Click OK to create itNavigation graphThe resource file introduces the newly created Fragment into the resource file

The new menu/bottom_nav_menu. XML

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@id/home_dest"
        android:icon="@drawable/ic_home"
        android:title="home" />
    <item
        android:id="@id/deep_link_dest"
        android:icon="@drawable/ic_android"
        android:title="dest" />
</menu>
Copy the code

Item. id = fragment.id = fragment.id = fragment.id = fragment.id

<?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/sample_navigation"
    app:startDestination="@id/home_dest">

    <fragment
        android:id="@+id/home_dest"
        . >.</fragment>
    <fragment
        android:id="@+id/one_dest"
        . >.</fragment>
    <fragment
        android:id="@+id/deep_link_dest"
        . />
</navigation>
Copy the code

Finally, create MainActivity and activity_main.xml. The activity_main.xml content is as follows:

<?xml version="1.0" encoding="utf-8"? >
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        app:defaultNavHost="true"
        app:navGraph="@navigation/sample_navigation" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_nav_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:menu="@menu/bottom_nav_menu" />

</LinearLayout>
Copy the code

MainActivity looks like this:

package com.cxl.jetpack.nav

import android.content.res.Resources
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.bottomnavigation.BottomNavigationView

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // The first step is to obtain NavHostFragment
        val host: NavHostFragment = supportFragmentManager
            .findFragmentById(R.id.my_nav_host_fragment) asNavHostFragment? ? :return
        // Get the NavController
        val navController = host.navController
        // Step 3 configure BottomNavigationView
        valbottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view) bottomNav? .setupWithNavController(navController)// Step 4 Add a route listener
        navController.addOnDestinationChangedListener { _, destination, _ ->
            val dest: String = try {
                resources.getResourceName(destination.id)
            } catch (e: Resources.NotFoundException) {
                destination.id.toString()
            }
            Toast.makeText(this@MainActivity."Navigated to $dest",
                Toast.LENGTH_SHORT).show()
            Log.d("NavigationActivity"."Navigated to $dest")}}}Copy the code

So the basic framework is in place.

home dest

Routing hop

No arguments to jump

OnViewCreated in HomeFragment (View: View, savedInstanceState: Bundle?) Add the following code to the function:

view.findViewById<Button>(R.id.open1).setOnClickListener(Navigation.createNavigateOnClickListener(R.id.open_one_action))
Copy the code

Where r.i.d.oppen_one_action is the action property we added to the Navigation graph resource as follows:

<?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/sample_navigation"
    app:startDestination="@id/home_dest">

    <fragment
        android:id="@+id/home_dest"
        android:name="com.cxl.jetpack.nav.HomeFragment"
        tools:layout="@layout/home_dest"
        android:label="HomeFragment" >
        <action
            android:id="@+id/open_one_action"
            app:destination="@id/one_dest"
            .
            />
    </fragment>
    <fragment
        android:id="@+id/one_dest"
        tools:layout="@layout/flow_step_one_dest"
        android:name="com.cxl.jetpack.nav.OneFragment"
        android:label="OneFragment" >
        <action
            android:id="@+id/action_one_dest_to_twoFragment"
            app:destination="@+id/tow_dest"
            . />
    </fragment>
    <fragment
        tools:layout="@layout/deep_link_dest"
        android:id="@+id/deep_link_dest"
        android:name="com.cxl.jetpack.nav.DeepLinkFragment"
        android:label="DeepLinkFragment" />
    <fragment
        tools:layout="@layout/flow_step_two_dest"
        android:id="@+id/tow_dest"
        android:name="com.cxl.jetpack.nav.TwoFragment"
        android:label="tow_dest" />
</navigation>
Copy the code

With reference to jump

We are now going to jump inside the TwoFragment with a parameter called text whose value covers the text value of the TextView whose ID is twoTxt.

Step 1 ModificationNavigation graphfile

Add the argument child to the fragment node whose Navigation graphid is tow_dest, as shown 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"
    android:id="@+id/sample_navigation"
    app:startDestination="@id/home_dest">.<fragment
        tools:layout="@layout/flow_step_two_dest"
        android:id="@+id/tow_dest"
        android:name="com.cxl.jetpack.nav.TwoFragment"
        android:label="tow_dest" >
        <argument
            android:name="text"
            app:argType="string"
            android:defaultValue="2"/>
    </fragment>
</navigation>
Copy the code

In build\generated\source\navigation-args\debug\com\ CXL \jetpack\nav, a TwoFragmentArgs class is generated.

OneFragment
onViewCreated(view: View, savedInstanceState: Bundle?)

 view.findViewById<Button>(R.id.open2).setOnClickListener {
    findNavController().navigate(OneFragmentDirections.actionOneDestToTwoFragment("Hi"))}Copy the code

Receive parameters

val arg : TwoFragmentArgs by navArgs()
view.findViewById<TextView>(R.id.twoTxt).text=arg.text
Copy the code

Remember to use Java8

Back to the home page

Next we go from TwoFragment back to HomeFragment.

configurationaction

<?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/sample_navigation"
    app:startDestination="@id/home_dest">

    <fragment
        android:id="@+id/home_dest"
        . />.<fragment
        android:id="@+id/tow_dest"
        . >.<action
            android:id="@+id/action_tow_dest_to_home_dest"
            app:popUpTo="@id/home_dest" />
    </fragment>
</navigation>
Copy the code

Note that app:popUpTo is used here, not destination. For app:popUpTo, see popUpTo and popUpToInclusive.

useNavigationReturn to the home page

Override fun onViewCreated in TwoFragment (View: View, savedInstanceState: Bundle?) Add the following code to the function:

/ / value
val arg : TwoFragmentArgs by navArgs()
view.findViewById<TextView>(R.id.twoTxt).text=arg.text
// Click the button to jump
view.findViewById<Button>(R.id.flow)
    .setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_tow_dest_to_home_dest))
Copy the code

useDeep LinkTo jump

General application scenarios of Deep Link: App pushes to open a specified page.

addDeep Link

The following code:

<?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/sample_navigation"
    app:startDestination="@id/home_dest">

    <fragment
        android:id="@+id/home_dest"
        ./>
    <fragment
        android:id="@+id/deep_link_dest"
        android:name="com.cxl.jetpack.nav.DeepLinkFragment"
        android:label="DeepLinkFragment"
        tools:layout="@layout/deep_link_dest">
        <argument
            android:name="dlValue"
            android:defaultValue="Deep Link"
            app:argType="string" />
        <deepLink
            android:id="@+id/deepLink"
            app:uri="https://cxl.cn/sample/nav/open-deep-link/{dlValue}" />
    </fragment>.</navigation>
Copy the code

Then add nav-graph in Manifests. XML as follows:

<?xml version="1.0" encoding="utf-8"? >
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">
    <application . >
        <activity name=".MainActivity" .>.<nav-graph android:value="@navigation/sample_navigation" />.</activity>
    </application>
</manifest>
Copy the code

The use of Deep Link

 override fun onViewCreated(view: View, savedInstanceState: Bundle?). {
        super.onViewCreated(view, savedInstanceState)
        val args : DeepLinkFragmentArgs by navArgs()
        view.findViewById<TextView>(R.id.dlTv).run {
            text = args.dlValue
            setOnClickListener {
                val bundle = Bundle()
                bundle.putString("dlValue"."Notification jump")
                val deepLink = findNavController()
                    .createDeepLink()
                    .setArguments(bundle)
                    .setDestination(R.id.deep_link_dest)
                    .createPendingIntent()
                valnotificationManager = context? .getSystemService(Context.NOTIFICATION_SERVICE)as NotificationManager
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    notificationManager.createNotificationChannel(NotificationChannel(
                        "Deep Link"."Deep Links", NotificationManager.IMPORTANCE_HIGH)
                    )
                }
                valbuilder = NotificationCompat.Builder( context!! ."Deep Link")
                    .setContentTitle("Notice")
                    .setContentText("Jump to Deep Link")
                    .setSmallIcon(R.drawable.ic_android)
                    .setContentIntent(deepLink)
                    .setAutoCancel(true)
                notificationManager.notify(0, builder.build())
            }
        }
    }
Copy the code

Click on the TextView to send a notification, and the user clicks on the notification to jump to the Deep Link to the page.

Source address :GitHub