Проверьте, есть ли навигационный график в фоновом стеке

#android #navigation #android-architecture-components #android-architecture-navigation

#Android #навигация #android-архитектура-компоненты #android-архитектура-навигация

Вопрос:

Мой навигационный график имеет auth подграф, содержащий LoginFragment и SignUpFragment:

 <navigation
    android:id="@ id/auth"
    app:startDestination="@id/loginFragment">
    <fragment
        android:id="@ id/signUpFragment"
        [...]
    <fragment
        android:id="@ id/loginFragment"
        [...]
    </fragment>
    [...]
</navigation>
 

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

 val currentDestId = navController.currentDestination?.id
if (currentDestId != R.id.loginFragment amp;amp; currentDestId != R.id.signUpFragment) {
    navController.navigate(
        NavGraphDirections.actionGlobalLogin()
    )
}
 

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

Мой текущий подход заключается в следующем:

 val authBackStack = try {
    navController.getBackStackEntry(R.id.auth)
} catch (t: Throwable) {
    null
}
if (authBackStack == null) {
    navController.navigate(
        NavGraphDirections.actionGlobalLogin()
    )
}
 

Идея здесь заключается в том, что getBackStackEntry выдает IllegalStateException , если переданный адресат (или график в данном случае) в данный момент не находится в заднем стеке. Мы используем это исключение в качестве индикатора, чтобы узнать, находится ли наш график в данный момент в заднем стеке или нет.

Является ли это допустимым подходом или он сломается в определенных сценариях? Или, может быть, есть даже лучший подход, чтобы проверить, содержит ли задний стек назначения определенного подграфа?

Комментарии:

1. Может быть, это будет полезно. popBackStack возвращает логическое значение. Основываясь на результатах, мы знаем, был ли пункт назначения в стеке. val hasAuthDestionation = findNavController().popBackStack(R.id.auth, false) if (!hasAuthDestionation) { findNavController().navigate(R.id.newDestination) } Кроме того, вы можете использовать инклюзивное «true», если это необходимо.

Ответ №1:

Это правильный подход, но вы можете скрыть его как функцию расширения следующим образом:

 fun NavController.isOnBackStack(@IdRes id: Int): Boolean = try { getBackStackEntry(id); true } catch(e: Throwable) { false }
 

Таким образом, вы фактически получаете желаемое логическое значение, скрывая поток управления на основе исключений (это требование из-за API, который предоставляет Jetpack Navigation).