Navigation Graph技术咨询:通用错误页、数据回调及跨导航跳转
1. 实现通用错误页面,消除重复定义
当前每个嵌套导航图都单独添加错误Fragment,导致重复代码冗余。解决方案是将错误Fragment统一放在主导航图中,所有子导航图直接复用,无需重复定义。
步骤:
- 在
main_navigation.xml中添加通用错误页的定义,移除各子导航图中的错误Fragment代码:
<navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/main_navigation" app:startDestination="@+id/home_navigation"> <!-- 原有嵌套导航图 --> <include app:graph="@navigation/home_navigation" /> <include app:graph="@navigation/explorer_navigation" /> <include app:graph="@navigation/favourite_navigation" /> <include app:graph="@navigation/server_navigation" /> <include app:graph="@navigation/settings_navigation" /> <!-- 全局通用错误页 --> <fragment android:id="@+id/fragment_error" android:name="com.xyz.android.ui.nodata.ErrorBaseFragment"> <argument android:name="title" android:defaultValue="NO_DATA" app:argType="string" /> <argument android:name="errorType" app:argType="com.xyz.android.ui.nodata.EnumErrorType" android:defaultValue="NO_DATA" /> <!-- 可选:自定义操作按钮文本 --> <argument android:name="actionText" android:defaultValue="RETRY" app:argType="string" /> </fragment> </navigation>
- 在任意子导航图的页面中,直接通过ID跳转至通用错误页,无需在子图中定义action:
// 示例:在SettingsBaseFragment中跳转错误页 val errorArgs = ErrorBaseFragmentArgs.Builder() .setTitle(getString(R.string.error_network_title)) .setErrorType(EnumErrorType.NETWORK_ERROR) .setActionText(getString(R.string.btn_retry)) .build() findNavController().navigate(R.id.fragment_error, errorArgs.toBundle())
2. 错误页点击按钮携带数据回调前一页
利用Navigation的SavedStateHandle返回结果API(2.3.0+版本支持),无需额外接口或ViewModel,直接实现数据回调。
步骤:
- 在跳转前的页面(如
SettingsBaseFragment)注册结果监听:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 监听错误页返回的操作结果 findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Boolean>("isRetry")?.observe(viewLifecycleOwner) { isRetry -> if (isRetry) { // 执行对应逻辑,比如重新加载数据 loadSettingsData() } } }
- 在错误页
ErrorBaseFragment的按钮点击事件中,传递数据并返回:
binding.btnAction.setOnClickListener { // 传递返回数据(支持布尔、字符串、Parcelable等类型) findNavController().previousBackStackEntry?.savedStateHandle?.set("isRetry", true) // 返回上一页 findNavController().popBackStack() }
如果需要传递复杂自定义对象,确保对象实现Parcelable或Serializable接口。
3. 子导航向父导航跳转其他目标(替代共享ViewModel)
推荐使用全局Action或直接导航目标ID,比共享ViewModel更简洁直接。
方案一:全局Action(推荐)
在主导航图中定义全局Action,指向目标页面,子导航图的页面可直接调用:
<!-- 在main_navigation.xml中添加全局跳转Action --> <action android:id="@+id/action_global_home_fragment" app:destination="@id/home_fragment" /> <!-- home_fragment是home_navigation中的目标ID -->
在子导航图的页面中调用:
// 示例:从Settings相关页面跳转到首页 findNavController().navigate(R.id.action_global_home_fragment)
方案二:直接导航目标ID
如果目标页面的ID在主导航图中可访问(包括子导航图内的目标),直接用ID跳转,Navigation会自动处理跨子图导航:
// 直接跳转到home_navigation的首页 findNavController().navigate(R.id.home_fragment) // 或直接跳转到整个home导航图(回到首页栈顶) findNavController().navigate(R.id.home_navigation)
内容的提问来源于stack exchange,提问作者Sneha Bansal
相关产品推荐
相关产品推荐

