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