Jetpack学习笔记:架构组件——Navigation之使用Safe Args传递数据

Safe Args简介

简介内容摘自 在目的地之间传递数据 | Android 开发者 | Android Developers

Navigation 组件具有一个名为 Safe Args 的 Gradle 插件,该插件可以生成简单的 object 和 builder 类,以便以类型安全的方式浏览和访问任何关联的参数。我们强烈建议您将 Safe Args 用于导航和数据传递,因为它可以确保类型安全。

在某些情况下您无法使用 Safe Args 插件,例如当您不使用 Gradle 时。在这些情况下,您可以使用 Bundle 直接传递数据。

如需将 Safe Args 添加到您的项目中,请在顶层 build.gradle 文件中包含以下 classpath:

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.3.2"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

您还必须应用以下两个可用插件之一。

如需生成适用于 Java 模块或 Java 和 Kotlin 混合模块的 Java 语言代码,请将以下行添加到应用或模块的 build.gradle 文件中:

apply plugin: "androidx.navigation.safeargs"

此外,如需生成适用于 Kotlin 独有的模块的 Kotlin 代码,请添加以下行:

apply plugin: "androidx.navigation.safeargs.kotlin"

根据迁移到 AndroidX 文档,您的 gradle.properties 文件中必须具有 android.useAndroidX=true。

启用 Safe Args 后,生成的代码会为每个操作包含以下类型安全的类和方法,以及每个发送和接收目的地。

  • 为生成操作的每一个目的地创建一个类。该类的名称是在源目的地的名称后面加上“Directions”。例如,如果源目的地是名为 SpecifyAmountFragment 的 Fragment,则生成的类的名称为 SpecifyAmountFragmentDirections。
    该类会为源目的地中定义的每个操作提供一个方法。

  • 对于用于传递参数的每个操作,都会创建一个 inner 类,该类的名称根据操作的名称确定。例如,如果操作名称为 confirmationAction,,则类名称为 ConfirmationAction。如果您的操作包含不带 defaultValue 的参数,则您可以使用关联的 action 类来设置参数值。

  • 为接收目的地创建一个类。该类的名称是在目的地的名称后面加上“Args”。例如,如果目的地 Fragment 的名称为 ConfirmationFragment,,则生成的类的名称为 ConfirmationFragmentArgs。可以使用该类的 fromBundle() 方法检索参数。

使用前准备

如官方文档所言,首先需要将Safe Args插件添加到项目中,并应用相关插件。

本文选择生成适用于Java模块的Java语言代码。添加插件的写法与文档有些不同,在build.gradle中这样添加:

plugins {
    id 'com.android.application'
    id 'androidx.navigation.safeargs'
}

阅读启用Safe Args后的说明,可以得知,启用该插件后,插件将根据目标(Destination)名和操作(Action)名来生成一些类和方法。因此,为了避免生成的类名和方法名过于复杂,需要对导航图进行调整,比如修改了action的id(自动生成的id太长了,会导致插件生成的类名和方法名同样很长)。


<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/mobile_navigation"
    app:startDestination="@+id/navigation_home">

    <fragment
        android:id="@+id/navigation_home"
        android:name="com.month.bottomnavigationdemo.ui.home.HomeFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_home" >
        <action
            android:id="@+id/action_jump"
            app:destination="@id/navigation_notifications">
            <argument
                android:name="param" />
        action>

    fragment>

    <fragment
        android:id="@+id/navigation_notifications"
        android:name="com.month.bottomnavigationdemo.ui.notifications.NotificationsFragment"
        android:label="@string/title_notifications"
        tools:layout="@layout/fragment_notifications" >
        <argument
            android:name="param"
            app:argType="string"
            android:defaultValue="unknown" />
    fragment>

navigation>

此处只展示了导航图中HomeFragment和NotificationsFragment的部分。请关注以下几个点:

  • HomeFragment中存在一个id为"action_jump",目标是NotificationFragment的action,且附带了一个名为“param”的参数,没有设置默认值
  • NotificationsFragment中存在一个名为“param”的参数,类型为“String”,默认值为“unknown”。

自动生成代码

完成上述操作后,Rebuild Project,Safe Args将自动生成相关的代码。
Jetpack学习笔记:架构组件——Navigation之使用Safe Args传递数据_第1张图片
可以看到,插件为我们生成了HomeFragmentDirections类以及NotificationsFragmentArgs类。Directions类对应行为,而Args类对应参数。由于导航图中只有HomeFragment设置了行为(action),同样也只有NotificationsFragment设置了参数(argument),因此只生成了这两个类,而没有生成HomeFragmentArgs类和NotificationsFragmentDirections类。

传递数据

有了以上这些类,就可以使用它们帮助我们传递数据了。

进入HomeFragment,修改按钮的点击事件,传递数据的方式有几种,下面分别介绍。

一、在Action中携带数据

首先获取到对应的Action,这个类的类名与导航图中action的id存在对应关系,并且由于没有设置默认值,生成的构造方法中要求填入一个对应类型的值。

//没有设置默认值的情况,需要填入参数
HomeFragmentDirections.ActionJump action = HomeFragmentDirections.actionJump("hello world!");
//设置了默认值,构造方法无参
//HomeFragmentDirections.ActionJump action = HomeFragmentDirections.actionJump();

除此之外,也可以使用set方法对对应的参数进行赋值。

action.setParam("bye~ world!");

最后通过NavController.navigate方法进行导航。

//HomeFragment
	@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Button button = getView().findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                HomeFragmentDirections.ActionJump action = HomeFragmentDirections.actionJump("hello world!");
                action.setParam("bye~ world!");
                NavController navController = Navigation.findNavController(v);
                navController.navigate(action);
            }
        });
    }

二、使用Bundle

这里的Bundle通过Args类的建造者模式创建,使用方法如下:

Bundle bundle = new NotificationsFragmentArgs.Builder().setParam("bye~ world!").build().toBundle();

完整的代码:

//HomeFragment
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Button button = getView().findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bundle bundle = new NotificationsFragmentArgs.Builder().setParam("bye~ world!").build().toBundle();
                NavController navController = Navigation.findNavController(v);
                navController.navigate(R.id.action_jump, bundle);
            }
        });
    }

获取数据

与传递数据相反,只要调用对应的Get方法即可。

//NotificationFragment
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        //获取参数
        if (getArguments() != null) {
            String param = NotificationsFragmentArgs.fromBundle(getArguments()).getParam();
            notificationsViewModel.setText(param);
        }
    }

Jetpack学习笔记:架构组件——Navigation之使用Safe Args传递数据_第2张图片

你可能感兴趣的:(java,android,移动开发,安卓)