Navigation 3 מייצג שינוי מהותי באופן שבו Jetpack Compose מטפל במצב הניווט, ומציע יתרונות ארכיטקטוניים משמעותיים בהשוואה ל-Navigation 2.
הסבר על השינויים בארכיטקטורה והשלבים הנדרשים להעברת אפליקציית Wear Compose מ-Navigation 2 ל-Navigation 3.
היתרונות העיקריים של Navigation 3
- שליטה ישירה במערך האחורי:
NavBackStackהוא בעצם רשימה משתנה של אובייקטים מסוגNavKey, שמייצגים את היסטוריית המסכים שהמשתמש ביקר בהם. אתם שולטים בה בדיוק כמו בכל רשימת KotlinMutableList (add, removeLast, clear). אתם יכולים לשנות את הרשימה ישירות כדי לבצע פעולות ניווט, כמו הוספת מקש כדי להתקדם או הסרת מקש כדי לחזור אחורה. - עיצוב שמתחיל ב-Compose: מקבץ הפעילויות הקודמות (back stack) מעוצב כמצב סטנדרטי שניתן לצפייה. שינוי היסטוריית הניווטים מתנהג בדיוק כמו עדכון של כל מצב אחר של 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
בניווט 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 וב-entryProvider DSL
הקונטיינר NavHost וה-DSL הפנימי שלו composable("route") { ... } builder
מוחלפים ב-NavDisplay וב-entryProvider {
entry<Key> { ... } } DSL.
לפני (ניווט 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() } } )