בקטעים הבאים מתוארות אסטרטגיות לשמירת מקבץ הפעילויות הקודמות ולאחסון המצב שמשויך לרשומות במקבץ הפעילויות הקודמות.
שמירת מקבץ הפעילויות הקודמות (back stack)
כדי לספק חוויית משתמש טובה, חשוב לוודא שמצב הניווט של האפליקציה נשמר באירועים שונים במחזור החיים, כולל שינויים בהגדרות והשבתת תהליכים. ב-Navigation 3, מקבץ הפעילויות הקודמות נמצא בבעלותכם, כך שאין הנחיות מחמירות לגבי האופן שבו צריך ליצור או לשמור אותו. עם זאת, ב-Navigation 3 יש שיטה נוחה שמספקת מקבץ פעילויות קודמות שניתן לשמור: rememberNavBackStack.
שימוש ב-rememberNavBackStack
הפונקציה הקומפוזבילית rememberNavBackStack נועדה ליצור מקבץ פעילויות קודמות (back stack) שנשמר גם כשמשנים את ההגדרות וגם כשמשביתים את התהליך.
כדי ש-rememberNavBackStack יפעל כמו שצריך, כל מפתח במקבץ הפעילויות הקודמות (back stack) צריך לעמוד בדרישות ספציפיות:
- הטמעת הממשק
NavKey: כל מפתח במקבץ הפעילויות הקודמות חייב להטמיע את הממשקNavKey. הוא משמש כממשק סמן שמאותת לספרייה שאפשר לשמור את המפתח. - הוספת האנוטציה
@Serializable: בנוסף להטמעה שלNavKey, צריך לסמן את המחלקות והאובייקטים העיקריים באנוטציה@Serializable.
בקטע הקוד הבא אפשר לראות הטמעה נכונה של rememberNavBackStack:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
זכירת מקבץ פעילויות קודמות (back stack) עם סוגי משנה של NavKey
הפונקציה הקומפוזבילית rememberNavBackStack מחזירה NavBackStack<NavKey>.
אם האפליקציה מגדירה סוג משנה משלה של NavKey שכל המקשים שלה יורשים ממנו, אפשר לשמר את ההקלדה הזו על ידי הטמעה של פונקציית remember בהתאמה אישית, באופן הבא:
@Serializable sealed interface MyAppNavKey : NavKey @Serializable data object ScreenA: MyAppNavKey @Serializable data class ScreenB(val id: String): MyAppNavKey @Composable fun rememberMyAppNavBackStack(vararg elements: MyAppNavKey): NavBackStack<MyAppNavKey> { return rememberSerializable(serializer = serializer()) { NavBackStack(*elements) } } @Composable fun MyApp() { // defaultNavBackStack is NavBackStack<NavKey> val defaultNavBackStack = rememberNavBackStack(ScreenA) // myAppNavBackStack is NavBackStack<MyAppNavKey> val myAppNavBackStack = rememberMyAppNavBackStack(ScreenA) }
במאמר NavBackStackSamples תוכלו למצוא דוגמאות נוספות, כולל איך לטפל בפולימורפיזם פתוח.
אפשרות חלופית: אחסון ב-ViewModel
דרך נוספת לנהל את מקבץ הפעילויות הקודמות היא לאחסן אותו ב-ViewModel.
כדי לשמור על עקביות במקרה של השבתת תהליך כשמשתמשים ב-ViewModel או בכל אחסון מותאם אישית אחר, צריך:
- ודאו שאפשר להעביר את המפתחות לסדרה: בדיוק כמו ב-
rememberNavBackStack, צריך לוודא שאפשר להעביר את מפתחות הניווט לסדרה. - טיפול ידני בסריאליזציה ובדה-סריאליזציה: אתם אחראים לשמור באופן ידני את הייצוג הסריאלי של כל מפתח באחסון מתמיד (למשל,
SharedPreferences, מסד נתונים או קובץ), ולבצע דה-סריאליזציה שלו כשהאפליקציה עוברת לרקע או משוחזרת.
הגדרת ההיקף של ViewModel מופעים ל-NavEntry אובייקטים
ViewModels משמשים לשמירת המצב שקשור לממשק המשתמש בשינויים בהגדרות, כמו סיבוב המסך. כברירת מחדל, ההיקף של ViewModels הוא ViewModelStoreOwner הקרוב ביותר, שהוא בדרך כלל Activity או Fragment.
עם זאת, יכול להיות שתרצו להגדיר את ההיקף של ViewModel ל-NavEntry ספציפי (כלומר, מסך או יעד ספציפיים) במקבץ הפעילויות הקודמות (back stack), במקום לכל ה-Activity. כך אפשר לוודא שהמצב של ViewModel נשמר רק בזמן ש-NavEntry הספציפי הוא חלק ממקבץ הפעילויות הקודמות, ונמחק כש-NavEntry נשלף.
ספריית התוספים של androidx.lifecycle:lifecycle-viewmodel-navigation3 מספקת NavEntryDecorator שמאפשר את זה. המעצב הזה מספק ViewModelStoreOwner לכל NavEntry. כשיוצרים ViewModel בתוך התוכן של NavEntry (למשל, באמצעות viewModel() ב-Compose), הוא מוגדר אוטומטית למפתח של NavEntry הספציפי הזה במקבץ הפעילויות הקודמות (back stack). כלומר, ה-ViewModel נוצר כשמוסיפים את ה-NavEntry למקבץ הפעילויות הקודמות (back stack), ונמחק כשמסירים אותו.
כדי להשתמש ב-NavEntryDecorator להגדרת ההיקף של ViewModel ב-NavEntry:
- מוסיפים את התלות
androidx.lifecycle:lifecycle-viewmodel-navigation3לקובץapp/build.gradle.kts. - מוסיפים את
rememberSaveableStateHolderNavEntryDecorator()שמוגדר כברירת מחדל לרשימת ה-entryDecoratorsכשיוצריםNavDisplay. - מוסיפים את
rememberViewModelStoreNavEntryDecorator()לרשימה שלentryDecorators.
NavDisplay( entryDecorators = listOf( // Add the default decorators for managing scenes and saving state rememberSaveableStateHolderNavEntryDecorator(), // Then add the view model store decorator rememberViewModelStoreNavEntryDecorator() ), backStack = backStack, entryProvider = entryProvider { }, )