בקטעים הבאים מוסבר על אסטרטגיות לשמירת מקבץ הפעילויות הקודמות (back stack) ולשמירת מצב שמשויך לרשומות במקבץ הפעילויות הקודמות (back stack).
שמירת מקבץ פעילויות קודמות (back stack)
כדי ליצור חוויית משתמש טובה, חשוב לוודא שמצב הניווט באפליקציה נשמר בכל מיני אירועים במחזור החיים, כולל שינויים בהגדרות וסיום תהליך. ב-Navigation 3, אתם הבעלים של מקבץ הפעילויות הקודמות (back stack), ולכן אין הנחיות מחמירות לגבי אופן היצירה או השמירה שלו. עם זאת, Navigation 3 מציע שיטה נוחה שמאפשרת לשמור את מקבץ הפעילויות הקודמות (back stack): rememberNavBackStack.
שימוש ב-rememberNavBackStack
הפונקציה הניתנת להגדרה rememberNavBackStack נועדה ליצור מקבץ פעילויות קודמות (back stack) שנשמרת גם אחרי שינויים בהגדרות וגם אחרי השבתת תהליך.
כדי שהלחצן rememberNavBackStack יפעל בצורה תקינה, כל מקש במקבץ פעילויות קודמות (back stack) צריך לעמוד בדרישות ספציפיות:
- הטמעה של הממשק
NavKey: כל מפתח במקבץ הפעילויות הקודמות (back stack) צריך להטמיע את הממשקNavKey. הוא פועל כממשק סמנים שמסמן לספרייה שאפשר לשמור את המפתח. - הוספת האנוטציה
@Serializable: בנוסף להטמעה שלNavKey, צריך לסמן את המחלקות והאובייקטים העיקריים באמצעות האנוטציה@Serializable.
בקטע הקוד הבא מוצגת הטמעה נכונה של rememberNavBackStack:
@Serializable data object Home : NavKey @Composable fun NavBackStack() { val backStack = rememberNavBackStack(Home) }
זכירת מקבץ פעילויות קודמות (back stack) עם סוגי משנה של NavKey
הפונקציה הניתנת להגדרה rememberNavBackStack מחזירה NavBackStack<NavKey>.
אם האפליקציה מגדירה סוג משנה משלה של NavKey שממנו כל המפתחות שלה מקבלים בירושה, אפשר לשמור על ההקלדה הזו על ידי הטמעה של פונקציית זכירה מותאמת אישית, באופן הבא:
@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
גישה נוספת לניהול מקבץ הפעילויות הקודמות (back stack) היא לאחסן אותה ב-ViewModel.
כדי שהנתונים יישמרו גם אחרי השבתת תהליך כשמשתמשים ב-ViewModel או בכל אחסון מותאם אישית אחר, צריך:
- לוודא שאפשר לבצע סריאליזציה של המקשים: בדיוק כמו ב-
rememberNavBackStack, צריך לוודא שאפשר לבצע סריאליזציה של מקשי הניווט. - טיפול ידני בסריאליזציה ובדה-סריאליזציה: אתם אחראים לשמירת הייצוג הסריאלי של כל מפתח ולאחזור שלו מאחסון קבוע (למשל,
SharedPreferences, מסד נתונים או קובץ) כשהאפליקציה עוברת לרקע או משוחזרת.
הגדרת היקף של ViewModel שניות ל-NavEntry שניות
המאפיינים ViewModels משמשים לשמירת מצב שקשור לממשק המשתמש במהלך שינויים בהגדרות, כמו סיבוב המסך. כברירת מחדל, ViewModels מוגדרים בהיקף של ViewModelStoreOwner הקרוב ביותר, בדרך כלל Activity או Fragment.
עם זאת, יכול להיות שתרצו להגדיר ViewModel לNavEntry ספציפי (כלומר, למסך או ליעד ספציפיים) במקבץ הפעילויות הקודמות, ולא לActivity כולו. כך מוודאים שהמצב של ViewModel נשמר רק בזמן שNavEntry המסוים הזה הוא חלק ממקבץ פעילויות קודמות (back stack), והוא מתנקה כשמוציאים את NavEntry מהערימה.
ספריית התוספים של androidx.lifecycle:lifecycle-viewmodel-navigation3 מספקת NavEntryDecorator שמקלה על התהליך הזה. הדקורטור הזה מספק ViewModelStoreOwner לכל NavEntry. כשיוצרים ViewModel בתוך תוכן של NavEntry (למשל באמצעות viewModel() ב-Compose), הוא מוגדר אוטומטית בהיקף של המפתח הספציפי של אותו NavEntry במקבץ פעילויות קודמות (back stack). כלומר, ViewModel נוצר כשמוסיפים את NavEntry למקבץ פעילויות קודמות (back stack), והוא מתנקה כשמסירים אותו.
כדי להשתמש ב-NavEntryDecorator כדי להגדיר את ההיקף של ViewModels ל-NavEntrys, פועלים לפי השלבים הבאים:
- מוסיפים את יחסי התלות של
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 { }, )