Navigation 3 представляет собой фундаментальный сдвиг в том, как Jetpack Compose обрабатывает состояние навигации, и предлагает значительные архитектурные преимущества по сравнению с Navigation 2.
Разберитесь в архитектурных изменениях и шагах, необходимых для миграции приложения Wear Compose с Navigation 2 на Navigation 3.
Основные преимущества навигации 3
- Прямое управление стеком возврата :
NavBackStack— это, по сути, изменяемый список объектовNavKey, представляющий историю посещенных пользователем экранов. Вы управляете им точно так же, как и любымMutableListKotlin (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() } } )