Navigation 3 thể hiện một sự thay đổi cơ bản trong cách Jetpack Compose xử lý trạng thái điều hướng và mang lại những lợi thế đáng kể về kiến trúc so với Navigation 2.
Tìm hiểu những thay đổi về cấu trúc và các bước cần thiết để di chuyển ứng dụng Wear Compose từ Navigation 2 sang Navigation 3.
Các ưu điểm chính của Navigation 3
- Kiểm soát trực tiếp ngăn xếp lui: Về cơ bản,
NavBackStackchỉ là một danh sách có thể thay đổi gồm các đối tượngNavKey, đại diện cho nhật ký màn hình mà người dùng đã truy cập. Bạn kiểm soát nó giống như cách bạn kiểm soát bất kỳMutableListKotlin nào (add,removeLast,clear). Bạn trực tiếp thao tác với danh sách để thực hiện các thao tác điều hướng, chẳng hạn như thêm khoá để chuyển tiếp hoặc xoá khoá để quay lại. - Thiết kế ưu tiên Compose: Ngăn xếp lui được mô hình hoá dưới dạng trạng thái có thể quan sát tiêu chuẩn. Việc sửa đổi nhật ký điều hướng hoạt động giống hệt như việc cập nhật bất kỳ trạng thái Compose nào khác, tự động kích hoạt quá trình kết hợp lại để hiển thị màn hình hiện tại.
- An toàn về kiểu theo mặc định: Các tuyến đường dựa trên chuỗi sẽ bị loại bỏ hoàn toàn. Chỉ đường sử dụng các đối tượng dữ liệu và lớp dữ liệu có thể chuyển đổi tuần tự.
- Trình bày tách biệt (Chiến lược cảnh): Lớp chuyển đổi giao diện người dùng (
NavDisplayvàSwipeDismissableSceneStrategy) hoàn toàn tách biệt với tính năng theo dõi trạng thái (NavBackStack), giúp đơn giản hoá việc tích hợp các hiệu ứng chuyển đổi điều hướng tích hợp sẵn của Wear OS.
Các bước di chuyển
1. Cập nhật phần phụ thuộc
Xoá phần phụ thuộc androidx.wear.compose:compose-navigation cũ và giới thiệu các phần phụ thuộc Navigation 3 mới được phân chia, cùng với khả năng hỗ trợ việc chuyển đổi tuần tự Kotlin.
Xoá:
implementation("androidx.wear.compose:compose-navigation:...")
Thêm:
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. Cập nhật đích đến để triển khai NavKey
Trong Navigation 2, bạn có thể đã sử dụng các chuỗi hoặc đối tượng chung để định tuyến. Trong Navigation 3, bạn phải triển khai giao diện của điểm đánh dấu NavKey và chú thích mọi đối tượng màn hình bằng @Serializable.
Tại sao yêu cầu điều này? Để ngăn xếp lui có thể được lưu và khôi phục trong quá trình bị buộc tắt, navigation3-runtime cơ bản sẽ dựa vào kotlinx-serialization để chuyển đổi trạng thái thành dữ liệu nối tiếp.
Trước (Navigation 2 – Tuyến đường chung an toàn về kiểu):
sealed class Nav2Screen { data object Landing : Nav2Screen() data object List : Nav2Screen() }
Sau (Điều hướng 3 – NavKey + Serializable):
@Serializable sealed interface MigrationScreen : NavKey { @Serializable data object Landing : MigrationScreen @Serializable data object List : MigrationScreen }
3. Thay thế Logic định tuyến (NavController thành NavBackStack)
Thay thế NavController bằng NavBackStack được khởi tạo bằng rememberNavBackStack. Bạn cũng cần tạo thực thể SwipeDismissableSceneStrategy dành riêng cho Wear OS.
Trước (Navigation 2):
val navController = rememberSwipeDismissableNavController()
Sau (Điều hướng 3):
val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey) val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()
4. Thay thế NavHost bằng NavDisplay và DSL entryProvider
Vùng chứa NavHost và DSL trình tạo composable("route") { ... } nội bộ của vùng chứa này được thay thế bằng NavDisplay và DSL entryProvider {
entry<Key> { ... } }.
Trước (Navigation 2):
SwipeDismissableNavHost(navController = navController, startDestination = "menu") { composable("menu") { GreetingScreen( onShowList = { navController.navigate("list") } ) } composable("list") { ListScreen() } }
Sau (Điều hướng 3):
NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { entry<MigrationScreen.Landing> { GreetingScreen( onShowList = { backStack.add(MigrationScreen.List) } ) } entry<MigrationScreen.List> { ListScreen() } } )