ניווט והמקבץ האחורי

השדה NavController מכיל 'מקבץ גיבוי' שמכיל את היעדים של המשתמשים ביקרת במקום. כשהמשתמש מנווט למסכים באפליקציה שלכם, NavController מוסיפה ומסירה יעדים למקבץ האחורי או ממנו.

בתור מקבץ, המקבץ האחורי הוא "האחרון נכנס", של מבנה הנתונים. לכן, NavController מעביר פריטים אל החלק העליון של המסך ומקפיץ אותם סטאק.

התנהגות בסיסית

אלה העובדות העיקריות שצריך לקחת בחשבון לגבי התנהגות הגב מקבץ:

  • יעד ראשון: כשהמשתמש פותח את האפליקציה, השדה NavController דוחפת את היעד הראשון לחלק העליון של המקבץ האחורי.
  • העברה למקבץ: כל שיחה NavController.navigate() דוחפת את היעד הנתון לראש הערימה.
  • יעד מוביל שקופץ: הקשה על למעלה או על חזרה מפעילה את NavController.navigateUp() וגם NavController.popBackStack() שיטות, בהתאמה. הם מקפיצים את היעד העליון מהמקבץ. לצפייה מידע נוסף על ההבדלים בדף עקרונות הניווט בין Up לבין Back.

חזרה לחלון הראשי

השיטה NavController.popBackStack() מנסה להקפיץ את הקובץ הנוכחי את היעד מהמקבץ האחורי ומנווטים ליעד הקודם. הזה מחזיר את המשתמש בצורה יעילה שלב אחד אחורה בהיסטוריית הניווט. הוא מחזיר ערך בוליאני שמציין אם הוא חזר בהצלחה ליעד.

חזרה ליעד ספציפי

אפשר גם להשתמש בpopBackStack() כדי לנווט ליעד מסוים. לבצע אז השתמשו באחד מעומסי-היתר שלו. יש כמה מודלים שמאפשרים לך להעביר למשל, מספר שלם id או מחרוזת route. עומסי היתר האלה של המשתמש ליעד שמשויך למזהה הנתון. ביקורתית, הם קופצים כל מה שמופיע על הערימה מעל היעד הזה.

גם עומסי היתר האלה מקבלים ערך בוליאני של inclusive. הוא קובע אם NavController צריך גם להקפיץ את היעד שצוין מהמקבץ האחורי אחרי שמנווטים אליו.

כדוגמה, נבחן את קטע הקוד הקצר הבא:

navController.popBackStack(R.id.destinationId, true)

כאן הערך של NavController מחזיר את היעד ליעד עם המזהה השלם destinationId. מכיוון שהערך של הארגומנט inclusive הוא true, NavController גם יקפיץ את היעד הנתון מהמקבץ האחורי.

טיפול בחלון קופץ שנכשל

כשה-popBackStack() יחזיר את הערך false, תתבצע קריאה נוספת אל הפונקציה NavController.getCurrentDestination() מחזירה null. המשמעות היא שיש לאפליקציה הקפיץ את היעד האחרון מהמקבץ. במקרה כזה, המשתמש יראה רק מסך ריק.

מצב כזה יכול להתרחש במקרים הבאים:

  • הערימה של popBackStack() לא הופצה.
  • הערימה הועברה על ידי popBackStack() ריקה.

כדי לפתור את הבעיה, צריך לנווט ליעד חדש או להתקשר למספר finish() על הפעילות שלך כדי לסיים אותה. קטע הקוד הבא מדגים את זה:

קוטלין

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish()
}

Java

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish();
}

חלון קופץ עבור יעד

כדי להסיר יעדים מהמקבץ האחורי כשמנווטים מיעד אחד בפונקציה אחרת, צריך להוסיף ארגומנט popUpTo() לפונקציה navigate() המשויכת שיחה. popUpTo() מורה לספריית הניווט להסיר יעדים מסוימים מהמקבץ האחורי כחלק מהשיחה אל navigate(). ערך הפרמטר הוא המזהה של יעד במקבץ האחורי. המזהה יכול להיות מספר שלם id או מחרוזת route.

אפשר לכלול ארגומנט לפרמטר inclusive עם הערך true כדי לציין שהיעד שציינת ב-popUpTo() צריך גם חלון קופץ עם מקבץ אחורי.

כדי ליישם את זה באופן פרוגרמטי, צריך להעביר את popUpTo() אל navigate() כחלק מ NavOptions עם inclusive מוגדר ל-true. אפשר לעשות את זה גם בקטע 'כתיבה' וגם צפיות.

שמירת המצב בחלון קופץ

כשמשתמשים ב-popUpTo כדי לנווט ליעד, אפשר לשמור את מקבץ גיבויים (backStack) והמצבים של כל היעדים שהופצו מהמקבץ האחורי. אפשר ואז לשחזר את המקבץ לאחור ואת היעדים כשמנווטים ליעד הזה במועד מאוחר יותר. כך אפשר לשמור מצב של יעד נתון כמה אשכולות חזרה.

כדי לעשות זאת באופן פרוגרמטי, צריך לציין את הערך saveState = true כשמוסיפים את popUpTo אל באפשרויות הניווט שלכם.

אפשר גם לציין restoreState = true באפשרויות הניווט כדי ישחזר באופן אוטומטי את המקבץ האחורי ואת המצב שמשויך היעד.

לדוגמה:

navController.navigate(
    route = route,
    navOptions =  navOptions {
        popUpTo<A>{ saveState = true }
        restoreState = true
    }
)

כדי להפעיל שמירה ושחזור של מצב ב-XML, צריך להגדיר את popUpToSaveState בתור true ו-restoreState בתור true בהתאמה ב-action המשויך.

דוגמה בפורמט XML

הנה דוגמה של popUpTo ב-XML, באמצעות פעולה:

<action
  android:id="@+id/action_a_to_b"
  app:destination="@id/b"
  app:popUpTo="@+id/a"
  app:popUpToInclusive="true"
  app:restoreState=”true”
  app:popUpToSaveState="true"/>

כתיבת דוגמה

הנה דוגמה מלאה לכך בכלי 'כתיבה':

@Composable
fun MyAppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
    startDestination: Any = A
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable<A> {
            DestinationA(
                onNavigateToB = {
                // Pop everything up to, and including, the A destination off
                // the back stack, saving the back stack and the state of its
                // destinations.
                // Then restore any previous back stack state associated with
                // the B destination.
                // Finally navigate to the B destination.
                    navController.navigate(route = B) {
                        popUpTo<A> {
                            inclusive = true
                            saveState = true
                        }
                        restoreState = true
                    }
                },
            )
        }
        composable<B> { DestinationB(/* ... */) }
    }
}

@Composable
fun DestinationA(onNavigateToB: () -> Unit) {
    Button(onClick = onNavigateToB) {
        Text("Go to A")
    }
}

באופן מפורט יותר, אפשר לשנות את האופן שבו מתקשרים ל-NavController.navigate() בדרכים הבאות:

// Pop everything up to the destination_a destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a")
}

// Pop everything up to and including the "destination_a" destination off
// the back stack before navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a") { inclusive = true }
}

// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
    launchSingleTop = true
}

למידע כללי על העברת אפשרויות אל NavController.navigate(), אפשר לעיין במאמר המדריך לניווט עם אפשרויות.

הבלטה באמצעות פעולות

כשמנווטים באמצעות פעולה, אפשר לבחור יעדים נוספים להקפצת מהמקבץ האחורי. לדוגמה, אם לאפליקציה שלכם יש תהליך התחברות ראשוני, פעם אחת משתמש התחבר, עליך להשבית את כל היעדים הקשורים להתחברות של המקבץ 'הקודם', כך שלחצן 'הקודם' לא יחזיר את המשתמשים להתחברות .

מקורות מידע נוספים

מידע נוסף זמין בדפים הבאים:

  • ניווט מעגלי: איך להימנע מעומס יתר לבצע סטאק במקרים שבהם תהליכי הניווט הם מעגליים.
  • יעדי תיבות דו-שיח: מידע על האופן שבו יעדים של תיבת דו-שיח מוצגים שיקולים ייחודיים לניהול המקבץ.