Как я могу создать динамическую / условную навигацию с Jetpack Navigation? - PullRequest
3 голосов
/ 15 января 2020

Я столкнулся с интересной проблемой при попытке выполнить sh dynamici c или условную навигацию с помощью библиотеки навигации Jetpack.

Цель, которую я имею в виду, - продолжать использовать nav_graph.xml для управления общей навигационной диаграммой, но одновременно допускает условную навигацию, основанную на некоторых факторах.

Я включил ниже некоторый код, который показывает, куда движется мое решение. Проблема в том, что для работы условной логики c по сути требуется много обслуживания.

Я действительно хочу, чтобы функция navigateToDashboard в этом примере могла выполняться без параметров или параметры, которые редко меняются. Например, вместо передачи NavDirections, возможно, передается некоторый идентификатор, который позволяет функции navigateToDashboard знать, какой NavDirections вернуть.

Код для класса, управляющего условными логами c.

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())
                )
        )
)

Глядя на сайт вызовов, вы могли видеть, как это может быть проблематично c. Если я когда-нибудь захочу добавить новое потенциальное место назначения, скажем, dashboardV3Fragment, то мне нужно будет go для каждого сайта вызовов и добавить еще Pair.

. Это почти сводит на нет цель иметь DynamicNavImpl класс. Так вот где я застрял. Я хочу иметь возможность инкапсулировать различные переменные, участвующие в принятии решения о том, в какой пункт назначения go сделать, но похоже, как реализовано NavDirections, я не могу.

1 Ответ

3 голосов
/ 24 января 2020

Я выбрал несколько разных подходов и наткнулся на то, что до сих пор не кажется идеальным, но работает для моего случая использования.

Я полностью отказался от идеи использования центральной динамо c Диспетчер навигации. Вместо этого я решил иметь «перенаправление» или «контейнер» Fragment, который решает, что Fragment показать.

Так вот новый код внутри DashboardRedirectFragment

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

Я использую это, регистрируя новое назначение в моем навигационном графе с именем dashboardRedirectFragment, и все, что в графе, которому требуется доступ к панели инструментов, использует назначение dashboardRedirectFragment.

Это полностью инкапсулирует динамические c навигационные логики c в перенаправлении Fragment и позволяет мне продолжать использовать свой навигационный граф, как и ожидалось.

...