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