Jetpack Navigation 在 fragment 间跳转时使用 Safe Args 传参数

发布时间: 2023-05-25 14:34:51 作者: 大象笔记

在一个 Android APP 中,需要由 Fragment A 跳转到 B 时进行传参,官方推荐使用 Safe Args。 Safe Args 主打的就是类型安全 (type-safety),测试了一下。

配置 build.gradle

SafeArgs 和导航组件的其它模块不太一样,它本身并不是一个 API,而是一个可以生成代码的 gradle 插件。 所以需要将它设置为 gradle 依赖,并且在构建时使其能够正确运行来生成所需的代码。

首先,在项目级 project build.gradle 中增加配置:

buildscript {
    dependencies {
        def nav_version = "2.5.2"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

注意:

app build.gradle 中增加:

plugins {
  id 'androidx.navigation.safeargs.kotlin'
}

如果是纯 kotlin 模块的话可以这样配置,如果是 java 的话,去掉 kotlin 就行了。 然后同步一下 gradle。

吐槽:Google 搞这些玩意,配置太复杂了。

Navigation XML 中定义参数

Android Studio 中打开 navigation xml 文件,点击目标 fragment (即,要跳转到的目标 fragment)。

在 Design 视图下,可以看到 Arguments 区域,点击加号,在弹出的 Add Argument 窗口中配置就可以了,这里倒是挺人性化的。

添加之后,会看到 XML 中对应 fragment 自动增加了 argument 配置:

<fragment
	android:id="@+id/nav_edit"
	android:name="com.sunzhongwei.someapp.ui.edit.EditFragment"
	android:label="@string/menu_edit"
	tools:layout="@layout/fragment_edit" >
	<argument
		android:name="id"
		app:argType="long"
		android:defaultValue="0L" />
</fragment>

自动生成代码

此时执行 build 操作,gradle 就会针对上面配置的参数,生成相应的代码。 否则 Android Studio 没法完成后面代码的自动提示。

由 Android 视图切换到 Project 视图 (麻烦),才能看到生成的代码,在目录:

app/build/generated/source/navigation-args

假设是由 HomeFragment 跳转到 EditFragment, 那么生成的主要有两个文件:

HomeFragmentDirections.kt

public class HomeFragmentDirections private constructor() {
  private data class ActionNavHomeToNavEdit(
    public val id: Long = 0L
  ) : NavDirections {
    public override val actionId: Int = R.id.action_nav_home_to_nav_edit

    public override val arguments: Bundle
      get() {
        val result = Bundle()
        result.putLong("id", this.id)
        return result
      }
  }

  // 注意这个 object,传递 args 就是通过这个地方
  public companion object {
    public fun actionNavHomeToNavEdit(id: Long = 0L): NavDirections = ActionNavHomeToNavEdit(id)
  }
}

EditFragmentArgs.kt:

public data class EditFragmentArgs(
  public val id: Long = 0L
) : NavArgs {
  public fun toBundle(): Bundle {
    val result = Bundle()
    result.putLong("id", this.id)
    return result
  }

  public fun toSavedStateHandle(): SavedStateHandle {
    val result = SavedStateHandle()
    result.set("id", this.id)
    return result
  }

  ...
}

设置 args 参数,并跳转

例如,在 RecyclerView 列表中,点击一个子项,跳转详情页

binding.root.setOnClickListener {
	val action = HomeFragmentDirections.actionNavHomeToNavEdit(item.id)
	it.findNavController().navigate(action)
}

解析 args 参数

例如,跳转目标是 EditFragment,那么在 EditFragment 中:

private val args: EditFragmentArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
	super.onViewCreated(view, savedInstanceState)

	val id = args.id
	println(id)

	// ...
}

其他

参考

我是一名山东烟台的开发者,联系作者