如何使用 Jetpack Navigation 创建 dynamic/conditional 导航?

How can I create dynamic/conditional navigation with Jetpack Navigation?

我在尝试使用 Jetpack Navigation 库完成动态或条件导航时遇到了一个有趣的问题。

我的目标是能够继续使用 nav_graph.xml 来管理整体导航图,但同时允许基于某些因素的条件导航。

我在下面包含了一些代码,这些代码显示了我的解决方案的发展方向。问题在于它本质上需要大量维护才能使未来的条件逻辑正常工作。

我真的希望示例中的 navigateToDashboard 函数能够在没有参数或很少更改的参数的情况下执行。例如,不是传递 NavDirections,而是传递一些标识符,让 navigateToDashboard 函数知道哪个 NavDirections 到 return。

class 管理条件逻辑的代码。

class DynamicNavImpl(private val featureFlagService: FeatureFlagService) : DynamicNav {

    override fun navigateToDashboard(navDirectionsMap: Map<Int, NavDirections>): NavDirections {
        val destinationIdRes = if (featureFlagService.isDashboardV2Enabled()) {
            R.id.dashboardV2Fragment
        } else {
            R.id.dashboardFragment
        }

        return navDirectionsMap[destinationIdRes] ?: handleNavDirectionsException(destinationIdRes)
    }

    private fun handleNavDirectionsException(destinationIdRes: Int): Nothing {
        throw IllegalStateException("Destination $destinationIdRes does not have an accompanying set of NavDirections. Are you sure you added NavDirections for it?")
    }
}

调用站点示例

navigate(
        dynamicNav.navigateToDashboard(
                mapOf(
                        Pair(R.id.dashboardFragment, PhoneVerificationFragmentDirections.phoneVerificationToDashboard()),
                        Pair(R.id.dashboardV2Fragment, PhoneVerificationFragmentDirections.phoneVerificationToDashboardV2())
                )
        )
)

navigate(
        dynamicNav.navigateToDashboard(
                mapOf(
                        Pair(R.id.dashboardFragment, EmailLoginFragmentDirections.emailLoginToDashboard()),
                        Pair(R.id.dashboardV2Fragment, EmailLoginFragmentDirections.emailLoginToDashboardV2())
                )
        )
)

查看调用站点,您会发现这可能是个问题。如果我想添加一个新的潜在目的地,比方说 dashboardV3Fragment,那么我必须前往每个呼叫站点并添加另一个 Pair.

这几乎违背了 DynamicNavImpl class 的目的。所以这就是我被困的地方。我希望能够封装决定去哪个目的地所涉及的各种变量,但似乎 NavDirections 是如何实现的,我无法做到。

我尝试了几种不同的方法,最后找到了一些感觉仍然不理想但适合我的用例的方法。

我完全放弃了使用中央动态导航管理器的想法。相反,我决定使用 "redirect" 或 "container" Fragment 来决定要显示的内容 Fragment

所以这是 DashboardRedirectFragment

中的新代码
childFragmentManager.beginTransaction().replace(
                R.id.dashboard_placeholder,
                if (featureFlagService.isDashboardV2Enabled()) {
                    DashboardV2Fragment.newInstance()
                } else {
                    DashboardFragment.newInstance()
                }
        ).commit()

我使用它的方式是在我的导航图中注册一个名为 dashboardRedirectFragment 的新目的地,并且图中需要访问仪表板的任何内容都使用 dashboardRedirectFragment 目的地。

这完全封装了重定向中的动态导航逻辑 Fragment,并允许我继续按预期使用我的导航图。