Перейти к навигации 3

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

Разберитесь в архитектурных изменениях и шагах, необходимых для миграции приложения Wear Compose с Navigation 2 на Navigation 3.

Основные преимущества навигации 3

  • Прямое управление стеком возврата : NavBackStack — это, по сути, изменяемый список объектов NavKey , представляющий историю посещенных пользователем экранов. Вы управляете им точно так же, как и любым MutableList Kotlin ( add , removeLast , clear ). Вы напрямую манипулируете списком для выполнения действий навигации, таких как добавление клавиши для перехода вперед или удаление клавиши для перехода назад.
  • Проектирование с приоритетом на создание диалогов : стек возврата моделируется как стандартное наблюдаемое состояние. Изменение истории навигации происходит точно так же, как и обновление любого другого состояния Compose, автоматически запуская перекомпозицию для отображения текущего экрана.
  • Типобезопасность по умолчанию : маршруты на основе строк полностью исключены. Навигация использует сериализуемые объекты данных и классы данных.
  • Разделение презентаций (стратегии сцен) : слой переходов пользовательского интерфейса ( NavDisplay и SwipeDismissableSceneStrategy ) полностью отделен от отслеживания состояния ( NavBackStack ), что упрощает интеграцию встроенных навигационных переходов Wear OS.

Этапы миграции

1. Обновите зависимости.

Удалите старую зависимость androidx.wear.compose:compose-navigation и добавьте новые разделенные зависимости Navigation 3, а также поддержку сериализации Kotlin.

Удалять:

implementation("androidx.wear.compose:compose-navigation:...")

Добавлять:

implementation("androidx.navigation3:navigation3-runtime:...") // State logic
implementation("androidx.navigation3:navigation3-ui:...")      // Display logic
implementation("androidx.wear.compose:compose-navigation3:...") // Wear gestures
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:...") // Requires compiler plugin

2. Обновите пункты назначения, чтобы внедрить NavKey

В Navigation 2 для маршрутизации могли использоваться строки или универсальные объекты. В Navigation 3 необходимо реализовать интерфейс маркера NavKey и аннотировать каждый объект экрана с помощью @Serializable .

Зачем это нужно? Чтобы гарантировать сохранение и восстановление стека возврата при завершении процесса, базовая navigation3-runtime использует kotlinx-serialization для сериализации состояния.

Перед этим (Навигация 2 — Типобезопасные маршруты общего назначения):

sealed class Nav2Screen {
    data object Landing : Nav2Screen()
    data object List : Nav2Screen()
}

После (Навигация 3 - NavKey + Serializable):

@Serializable
sealed interface MigrationScreen : NavKey {
    @Serializable
    data object Landing : MigrationScreen

    @Serializable
    data object List : MigrationScreen
}

3. Замените логику маршрутизации ( NavController на NavBackStack ).

Замените ваш NavController на NavBackStack , инициализированный с помощью rememberNavBackStack . Вам также необходимо создать экземпляр SwipeDismissableSceneStrategy специально для Wear OS.

До (Навигация 2):

val navController = rememberSwipeDismissableNavController()

После (Навигация 3):

val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey)
val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()

4. Замените NavHost на NavDisplay и DSL entryProvider .

Контейнер NavHost и его внутренний DSL-фреймворк composable("route") { ... } заменяются на NavDisplay и DSL- entryProvider { entry<Key> { ... } } .

До (Навигация 2):

SwipeDismissableNavHost(navController = navController, startDestination = "menu") {
    composable("menu") {
        GreetingScreen(
            onShowList = { navController.navigate("list") }
        )
    }
    composable("list") {
        ListScreen()
    }
}

После (Навигация 3):

NavDisplay(
    backStack = backStack,
    sceneStrategies = listOf(strategy),
    entryProvider = entryProvider {
        entry<MigrationScreen.Landing> {
            GreetingScreen(
                onShowList = { backStack.add(MigrationScreen.List) }
            )
        }
        entry<MigrationScreen.List> {
            ListScreen()
        }
    }
)