Navigation 3은 Jetpack Compose가 탐색 상태를 처리하는 방식의 근본적인 변화를 나타내며 Navigation 2에 비해 상당한 아키텍처 이점을 제공합니다.
Wear Compose 앱을 Navigation 2에서 Navigation 3으로 이전하는 데 필요한 아키텍처 변경사항과 단계를 알아봅니다.
Navigation 3의 주요 이점
- 직접 백 스택 제어:
NavBackStack은 기본적으로NavKey객체의 변경 가능한 목록으로, 사용자가 방문한 화면의 기록을 나타냅니다. KotlinMutableList(add,removeLast,clear)와 마찬가지로 정확하게 제어합니다. 목록을 직접 조작하여 앞으로 이동하는 키를 추가하거나 뒤로 이동하는 키를 삭제하는 등의 탐색 작업을 실행합니다. - Compose 우선 설계: 백 스택은 표준 관찰 가능한 상태로 모델링됩니다. 탐색 기록을 수정하는 것은 다른 Compose 상태를 업데이트하는 것과 정확히 동일하게 동작하며, 현재 화면을 표시하기 위해 리컴포지션을 자동으로 트리거합니다.
- 기본적으로 유형 안전: 문자열 기반 경로가 완전히 삭제됩니다. 탐색은 직렬화 가능한 데이터 객체와 데이터 클래스를 활용합니다.
- 분리된 프레젠테이션 (장면 전략): UI 전환 레이어
(
NavDisplay및SwipeDismissableSceneStrategy)는 상태 추적 (NavBackStack)과 완전히 분리되어 기본 제공 Wear OS 탐색 전환을 더 간단하게 통합할 수 있습니다.
이전 단계
1. 종속 항목 업데이트
이전 androidx.wear.compose:compose-navigation 종속 항목을 삭제하고 Kotlin 직렬화 지원과 함께 새로운 분할 Navigation 3 종속 항목을 도입합니다.
삭제:
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을 사용하여 상태를 직렬화합니다.
이전 (Navigation 2 - 일반 유형 안전 경로):
sealed class Nav2Screen { data object Landing : Nav2Screen() data object List : Nav2Screen() }
이후 (Navigation 3 - NavKey + 직렬화 가능):
@Serializable sealed interface MigrationScreen : NavKey { @Serializable data object Landing : MigrationScreen @Serializable data object List : MigrationScreen }
3. 라우팅 로직 (NavController에서 NavBackStack으로) 바꾸기
NavController를 NavBackStack을 통해 초기화된
rememberNavBackStack으로 바꿉니다. 또한 Wear OS에 맞게
SwipeDismissableSceneStrategy를 인스턴스화해야 합니다.
이전 (Navigation 2):
val navController = rememberSwipeDismissableNavController()
이후 (Navigation 3):
val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey) val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()
4. NavHost를 NavDisplay 및 entryProvider DSL로 바꾸기
NavHost 컨테이너와 내부 composable("route") { ... } 빌더
DSL은 NavDisplay 및 entryProvider {
entry<Key> { ... } } DSL로 바뀝니다.
이전 (Navigation 2):
SwipeDismissableNavHost(navController = navController, startDestination = "menu") { composable("menu") { GreetingScreen( onShowList = { navController.navigate("list") } ) } composable("list") { ListScreen() } }
이후 (Navigation 3):
NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { entry<MigrationScreen.Landing> { GreetingScreen( onShowList = { backStack.add(MigrationScreen.List) } ) } entry<MigrationScreen.List> { ListScreen() } } )