במדריך הזה מוסבר איך להחליף מסלולים מבוססי-מחרוזות בסוגי Kotlin שניתנים לסריאליזציה, כדי להשיג בטיחות בזמן הקומפילציה ולמנוע קריסות בזמן הריצה שנגרמות בגלל שגיאות הקלדה או סוגי ארגומנטים שגויים.
דרישות מוקדמות
לפני שמתחילים בהעברה, צריך לוודא שהפרויקט עומד בדרישות הבאות:
- גרסת הניווט: צריך לעדכן ל-Jetpack Navigation 2.8.0 ואילך
- הפלאגין Kotlin serialization:
- מוסיפים את הפלאגין אל
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" }
- מוסיפים את יחסי התלות לקובץ
build.gradle.ktsברמה העליונה ולקובץbuild.gradle.ktsברמת המודול.
שלב 1: הגדרת היעדים
מחליפים את מחרוזות הנתיבים הקבועות באובייקטים ובסוגים של @Serializable.
- למסכים ללא ארגומנטים: משתמשים ב-
data object - למסכים עם ארגומנטים: משתמשים ב-
data class
לפני (מבוסס על מחרוזת):
const val ROUTE_HOME = "home"
const val ROUTE_PROFILE = "profile/{userId}"
אחרי (בטוח לסוג):
import kotlinx.serialization.Serializable
@Serializable
object Home
@Serializable
data class Profile(val userId: String)
שלב 2: מעדכנים את ההגדרה של NavHost
כדי להשתמש בסוגים הגנריים החדשים בפונקציות composable ו-dialog, צריך לעדכן את NavHost.
לפני:
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(...) }
composable("profile/{userId}") { backStackEntry ->
val userId = backStackEntry.arguments?.getString("userId")
ProfileScreen(userId)
}
}
אחרי:
NavHost(navController, startDestination = Home) {
composable<Home> {
HomeScreen(...)
}
composable<Profile> { backStackEntry ->
// The library automatically handles argument extraction
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(profile.userId)
}
}
שלב 3: הטמעה של קריאות ניווט בטוחות לסוגים
החלפת קריאות ניווט עם אינטרפולציה של מחרוזות במופעים של מחלקות.
לפני:
navController.navigate("profile/user123")
אחרי:
navController.navigate(Profile(userId = "user123"))
שלב 4: גישה לארגומנטים ב-ViewModels
אם אתם משתמשים ב-ViewModel, עכשיו אתם יכולים לחלץ את אובייקט המסלול ישירות מ-SavedStateHandle.
הטמעה:
class ProfileViewModel(
savedStateHandle: SavedStateHandle
) : ViewModel() {
// Automatically parses arguments into the Profile class
private val profile = savedStateHandle.toRoute<Profile>()
val userId = profile.userId
}
שלב 5: (מתקדם) טיפול בסוגים מותאמים אישית
אם אתם צריכים להעביר מחלקות נתונים מורכבות (לא רק פרימיטיבים), אתם צריכים להגדיר NavTypeמותאם אישית.
- יצירת סוג מותאם אישית:
```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)
) { ... }
שיטות מומלצות וטיפים
- היררכיות סגורות: באפליקציות גדולות, כדאי לקבץ את המסלולים באמצעות ממשק או מחלקה סגורים כדי לשמור על מבנה הניווט מאורגן.
- מופעים של אובייקטים: במסלולים ללא פרמטרים, תמיד משתמשים ב-
objectבמקום ב-classכדי להימנע מהקצאות מיותרות. - סוגים שניתן להגדיר כ-nullable: ה-API החדש תומך בסוגים שניתן להגדיר כ-nullable (לדוגמה,
data class Search(val query: String?)) ומספק ערכי ברירת מחדל באופן אוטומטי - בדיקה: אפשר להשתמש ב-
navController.currentBackStackEntry?.hasRoute<T>()כדי לבדוק את היעד הנוכחי בצורה בטוחה במהלך בדיקות של ממשק המשתמש