在一个 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"
}
}
注意:
- 需要放到 plugins 部分之上。如果放在下方会报错。
- 版本号需要跟 app build.gradle 中的 navigation 依赖保持一致
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, 那么生成的主要有两个文件:
- EditFragmentArgs: 用于解析 args。
- HomeFragmentDirections: 用于设置 args。基于 action 生成,即,navigation xml 中两个 fragment 间的连线。
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)
// ...
}
其他
- safe args 是否可以传递对象?
- 太麻烦了,真不如用 bundle。为了个类型安全,完全不值得。官方的说法是,只在无法使用 gradle 按照 safe args 插件时,才推荐使用 bundle 传递参数。
参考
- 注意不要参考 google 中文的文档,已经过时了。需要参考官方的英文文档:https://developer.android.com/guide/navigation/navigation-pass-data
- 谷歌开发者公众号文章中的介绍:https://mp.weixin.qq.com/s/sEUkAQMwxqEn16O4SfXZ1Q
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式