Hướng dẫn này trình bày quy trình thay thế các tuyến dựa trên chuỗi bằng các loại Kotlin có thể chuyển đổi tuần tự để đạt được độ an toàn trong thời gian biên dịch và loại bỏ các sự cố trong thời gian chạy do lỗi chính tả hoặc các loại đối số không chính xác.
Điều kiện tiên quyết
Trước khi bắt đầu di chuyển, hãy xác minh rằng dự án của bạn đáp ứng các yêu cầu sau:
- Phiên bản điều hướng: Cập nhật lên Jetpack Navigation 2.8.0 trở lên
- Trình bổ trợ chuyển đổi tuần tự Kotlin:
- Thêm trình bổ trợ vào
libs.versions.toml:
[libraries]
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
[plugins]
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
- Thêm các phần phụ thuộc vào
build.gradle.ktscấp cao nhất vàbuild.gradle.ktscấp mô-đun.
Bước 1: Xác định đích đến
Thay thế các chuỗi tuyến đường hằng số bằng các đối tượng và lớp @Serializable.
- Đối với các màn hình không có đối số: Sử dụng
data object - Đối với các màn hình có đối số: Sử dụng
data class
Trước (dựa trên chuỗi):
const val ROUTE_HOME = "home"
const val ROUTE_PROFILE = "profile/{userId}"
Sau (an toàn về kiểu):
import kotlinx.serialization.Serializable
@Serializable
object Home
@Serializable
data class Profile(val userId: String)
Bước 2: Cập nhật cấu hình NavHost
Cập nhật NavHost để sử dụng các loại chung mới trong hàm composable và dialog.
Trước:
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(...) }
composable("profile/{userId}") { backStackEntry ->
val userId = backStackEntry.arguments?.getString("userId")
ProfileScreen(userId)
}
}
Sau:
NavHost(navController, startDestination = Home) {
composable<Home> {
HomeScreen(...)
}
composable<Profile> { backStackEntry ->
// The library automatically handles argument extraction
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(profile.userId)
}
}
Bước 3: Triển khai các lệnh gọi điều hướng an toàn về kiểu
Thay thế các lệnh gọi điều hướng được nội suy chuỗi bằng các thực thể lớp.
Trước:
navController.navigate("profile/user123")
Sau:
navController.navigate(Profile(userId = "user123"))
Bước 4: Truy cập vào các đối số trong ViewModel
Nếu sử dụng ViewModel, giờ đây, bạn có thể trích xuất đối tượng tuyến đường trực tiếp từ SavedStateHandle.
Triển khai:
class ProfileViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
// Automatically parses arguments into the Profile class
private val profile = savedStateHandle.toRoute<Profile>()
val userId = profile.userId
}
Bước 5: (Nâng cao) Xử lý các loại tuỳ chỉnh
Nếu cần truyền các lớp dữ liệu phức tạp (không chỉ là các kiểu dữ liệu nguyên thuỷ), bạn phải xác định một NavType tuỳ chỉnh.
- Tạo kiểu tuỳ chỉnh:
```kotlin
val SearchFilterType = object : NavType
(isNullableAllowed = false) { override fun get(bundle: Bundle, key: String): SearchFilter? = Json.decodeFromString(bundle.getString(key) ?: return null)
override fun parseValue(value: String): SearchFilter =
Json.decodeFromString(Uri.decode(value))
override fun put(bundle: Bundle, key: String, value: SearchFilter) {
bundle.putString(key, Json.encodeToString(value))
}
}
2. **Register it in the Graph**:
```kotlin
composable<Search>(
typeMap = mapOf(typeOf<SearchFilter>() to SearchFilterType)
) { ... }
Mẹo và các phương pháp hay nhất
- Hệ phân cấp khép kín: Đối với các ứng dụng lớn, hãy nhóm các tuyến đường bằng cách sử dụng một giao diện hoặc lớp khép kín để duy trì cấu trúc điều hướng có tổ chức
- Các thực thể đối tượng: Đối với các tuyến đường không có tham số, hãy luôn sử dụng
objectthay vìclassđể tránh phân bổ không cần thiết - Các kiểu có thể rỗng: API mới hỗ trợ các kiểu có thể rỗng (ví dụ:
data class Search(val query: String?)) và tự động cung cấp các giá trị mặc định - Kiểm thử: Sử dụng
navController.currentBackStackEntry?.hasRoute<T>()để kiểm tra đích đến hiện tại theo cách an toàn về kiểu trong quá trình kiểm thử giao diện người dùng