הוספת תמיכה בתנועת החזרה החזויה

איור 1. מודל של מראה ומאפייני התנועה החוזרת לניווט עם חיזוי בטלפון

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

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

החל מ-Android 15, האפשרות למפתחים להפעלת אנימציות של חיזוי תנועת החזרה לא זמינה יותר. אנימציות מערכת כמו חזרה למסך הבית, מעבר בין משימות ומעבר בין פעילויות מוצגות עכשיו באפליקציות שהופעלה בהן תנועת החזרה החזויה, באופן מלא או ברמת הפעילות.

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

כדי לתמוך בתנועת החזרה החזויה, צריך לעדכן את האפליקציה באמצעות OnBackPressedCallback AppCompat 1.6.0-alpha05 (AndroidX) או API גבוה יותר שתואם לאחור, או באמצעות פלטפורמת ה-API החדשה OnBackInvokedCallback. רוב האפליקציות משתמשות ב-AndroidX API שתואם לאחור.

העדכון הזה מספק נתיב העברה ליירוט נכון של ניווט אחורה. במסגרת ההעברה, צריך להחליף את היירוטים של ניווט אחורה מ-KeyEvent.KEYCODE_BACK ומכל המחלקות עם שיטות onBackPressed כמו Activity ו-Dialog בממשקי ה-API החדשים של המערכת לניווט אחורה.

סרטון Codelab ו-Google I/O

בנוסף לשימוש בתיעוד שבדף הזה, כדאי לנסות את ה-Codelab שלנו. הוא מספק הטמעה של תרחיש שימוש נפוץ ב-WebView שמטפל בתנועת החזרה החזויה באמצעות ממשקי AndroidX Activity API.

אפשר גם לצפות בסרטון Google I/O שלנו, שכולל דוגמאות נוספות להטמעה של AndroidX וממשקי API של הפלטפורמה.

עדכון אפליקציה שמשתמשת בניווט חזרה שמוגדר כברירת מחדל

התכונה 'חזרה עם חיזוי' מופעלת כברירת מחדל.

אם האפליקציה שלכם משתמשת ב-Fragments או ב-Navigation Component, צריך גם לשדרג ל-AndroidX Activity 1.6.0-alpha05 ומעלה.

עדכון אפליקציה שמשתמשת בניווט מותאם אישית אחורה

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

האפליקציה משתמשת ב-AndroidX איך האפליקציה מטפלת בניווט אחורה נתיב ההעברה המומלץ (קישור בדף הזה)
כן ‫AndroidX APIs העברת הטמעה קיימת של AndroidX back
ממשקי API של פלטפורמות שלא נתמכות העברה של אפליקציית AndroidX שמכילה ממשקי API של ניווט אחורה שלא נתמכים אל ממשקי AndroidX API
לא ממשקי API של פלטפורמות שלא נתמכות, אפשר להעביר העברת אפליקציה שמשתמשת בממשקי API לא נתמכים של ניווט אחורה אל ממשקי API של הפלטפורמה
ממשקי API של פלטפורמות לא נתמכות, אבל אי אפשר להעביר כדי להשבית את ההסכמה באופן זמני, מגדירים את המאפיין android:enableOnBackInvokedCallback לערך false בתג <application> או <activity> בקובץ AndroidManifest.xml של האפליקציה.

העברה של הטמעה של ניווט אחורה ב-AndroidX

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

כדי לוודא שממשקי API שכבר משתמשים ב-OnBackPressedDispatcher (כמו Fragments ו-Navigation Component) פועלים בצורה חלקה עם תנועת החזרה החזויה, צריך לשדרג ל-AndroidX Activity 1.6.0-alpha05.

```xml
// In your build.gradle file:
dependencies {

// Add this in addition to your other dependencies
implementation "androidx.activity:activity:1.6.0-alpha05"
```

העברה של אפליקציית AndroidX שמכילה ממשקי API לא נתמכים של ניווט אחורה אל AndroidX APIs

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

כדי להעביר ממשקי API לא נתמכים אל AndroidX APIs:

  1. מעבירים את הלוגיקה של הטיפול בפעולת החזרה במערכת אל OnBackPressedDispatcher של AndroidX עם הטמעה של OnBackPressedCallback. הנחיות מפורטות זמינות במאמר בנושא הוספת ניווט מותאם אישית אחורה.

  2. משביתים את OnBackPressedCallback כשמוכנים להפסיק את היירוט של תנועת החזרה.

  3. מפסיקים את היירוט של אירועי חזרה באמצעות OnBackPressed או KeyEvent.KEYCODE_BACK.

  4. חשוב לשדרג לגרסה AndroidX Activity 1.6.0-alpha05.

    // In your build.gradle file:
    dependencies {
    
    // Add this in addition to your other dependencies
    implementation "androidx.activity:activity:1.6.0-alpha05"
    

העברה של אפליקציה שמשתמשת בממשקי API לא נתמכים של ניווט אחורה אל ממשקי API של הפלטפורמה

אם האפליקציה לא יכולה להשתמש בספריות AndroidX, ובמקום זאת היא מטמיעה או מפנה לניווט אחורה מותאם אישית באמצעות ממשקי API לא נתמכים, צריך לבצע מיגרציה ל-OnBackInvokedCallback platform API.

כדי להעביר ממשקי API שלא נתמכים אל פלטפורמת ה-API, צריך לבצע את השלבים הבאים:

  1. מומלץ להשתמש בממשק ה-API החדש OnBackInvokedCallback במכשירים עם Android 13 ומעלה, ולהסתמך על ממשקי ה-API שלא נתמכים במכשירים עם Android 12 ומטה.

  2. רושמים את הלוגיקה המותאמת אישית של החזרה ב-OnBackInvokedCallback באמצעות onBackInvokedDispatcher. כך הפעילות הנוכחית לא מסתיימת, והקריאה החוזרת מקבלת הזדמנות להגיב לפעולת החזרה אחרי שהמשתמש מסיים את הניווט חזרה במערכת.

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

    דוגמה להעברת לוגיקה מ-onBackPressed:

    Kotlin

    @Override
    fun onCreate() {
        if (BuildCompat.isAtLeastT()) {
            onBackInvokedDispatcher.registerOnBackInvokedCallback(
                OnBackInvokedDispatcher.PRIORITY_DEFAULT
            ) {
                /**
                 * onBackPressed logic goes here. For instance:
                 * Prevents closing the app to go home screen when in the
                 * middle of entering data to a form
                 * or from accidentally leaving a fragment with a WebView in it
                 *
                 * Unregistering the callback to stop intercepting the back gesture:
                 * When the user transitions to the topmost screen (activity, fragment)
                 * in the BackStack, unregister the callback by using
                 * OnBackInvokeDispatcher.unregisterOnBackInvokedCallback
                 * (https://developer.android.com/reference/kotlin/android/window/OnBackInvokedDispatcher#unregisteronbackinvokedcallback)
                 */
            }
        }
    }

    Java

    @Override
    void onCreate() {
      if (BuildCompat.isAtLeastT()) {
        getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
            OnBackInvokedDispatcher.PRIORITY_DEFAULT,
            () -> {
              /**
               * onBackPressed logic goes here - For instance:
               * Prevents closing the app to go home screen when in the
               * middle of entering data to a form
               * or from accidentally leaving a fragment with a WebView in it
               *
               * Unregistering the callback to stop intercepting the back gesture:
               * When the user transitions to the topmost screen (activity, fragment)
               * in the BackStack, unregister the callback by using
               * OnBackInvokeDispatcher.unregisterOnBackInvokedCallback
               * (https://developer.android.com/reference/kotlin/android/view/OnBackInvokedDispatcher#unregisteronbackinvokedcallback)
               */
            }
        );
      }
    }
  4. כדי להפסיק את היירוט של אירועי חזרה, משתמשים ב-OnBackPressed או ב-KeyEvent.KEYCODE_BACK ב-Android מגרסה 13 ואילך.

אפשר לרשום OnBackInvokedCallback באמצעות PRIORITY_DEFAULT או PRIORITY_OVERLAY, שלא זמין ב-AndroidX OnBackPressedCallback. רישום של קריאה חוזרת באמצעות PRIORITY_OVERLAY יכול להיות שימושי במקרים מסוימים.

זה קורה כשמבצעים מיגרציה מ-onKeyPreIme() והקריאה החוזרת צריכה לקבל את תנועת החזרה במקום לפתוח IME. ממשקי IME רושמים קריאות חוזרות (callback) ב-PRIORITY_DEFAULT כשהם נפתחים. צריך לרשום את פונקציית ה-callback ב-PRIORITY_OVERLAY כדי לוודא ש-OnBackInvokedDispatcher שולח את תנועת החזרה לפונקציית ה-callback במקום לפתוח את ה-IME.

ביטול ההסכמה לחיזוי החזרה

כדי לבטל את ההסכמה, בתג <application> ב-AndroidManifest.xml, מגדירים את הדגל android:enableOnBackInvokedCallback לערך false.

<application
    ...
    android:enableOnBackInvokedCallback="false"
    ... >
...
</application>

אם מגדירים את האפשרות הזו כ-False, מתבצעות הפעולות הבאות:

  • ההגדרה הזו משביתה את אנימציית המערכת של חיזוי תנועת החזרה.
  • התעלמות מ-OnBackInvokedCallback, אבל שיחות OnBackPressedCallback ממשיכות לפעול.

סירוב ברמת הפעילות

החל מ-Android 16, אפשר להשתמש בדגל android:enableOnBackInvokedCallback כדי להשבית את האנימציות החזויות של המערכת ברמת הפעילות. ההתנהגות הזו מאפשרת לנהל בקלות רבה יותר את המעבר של אפליקציות גדולות עם כמה פעילויות לתנועות ניווט חזויות.

בדוגמה הבאה מוצג הקוד של enableOnBackInvokedCallback עם הערך שמאפשר את האנימציה של המערכת לחזרה למסך הבית מ-MainActivity:

<manifest ...>
    <application . . .

        android:enableOnBackInvokedCallback="false">

        <activity
            android:name=".MainActivity"
            android:enableOnBackInvokedCallback="true"
            ...
        </activity>
        <activity
            android:name=".SecondActivity"
            android:enableOnBackInvokedCallback="false"
            ...
        </activity>
    </application>
</manifest>

כשמשתמשים בדגל android:enableOnBackInvokedCallback, חשוב לזכור את הנקודות הבאות:

  • ההגדרה android:enableOnBackInvokedCallback=false משביתה את האנימציות של החזרה החזויה אחורה ברמת הפעילות או ברמת האפליקציה, בהתאם למיקום שבו הגדרתם את התג, ומורה למערכת להתעלם מקריאות ל-API של פלטפורמת OnBackInvokedCallback. עם זאת, הקריאות אל OnBackPressedCallback ממשיכות לפעול כי OnBackPressedCallback תואם לאחור וקורא ל-API‏ onBackPressed, שלא נתמך בגרסאות קודמות ל-Android 13.
  • הגדרת הדגל enableOnBackInvokedCallback ברמת האפליקציה קובעת את ערך ברירת המחדל לכל הפעילויות באפליקציה. אפשר לשנות את ברירת המחדל לכל פעילות בנפרד על ידי הגדרת הדגל ברמת הפעילות, כמו שמוצג בדוגמת הקוד הקודמת.

שיטות מומלצות לשימוש בתכונת ההתקשרות חזרה

ריכזנו כאן שיטות מומלצות לשימוש בקריאות החוזרות הנתמכות של המערכת לביטול פעולה: BackHandler (ב-Compose),‏ OnBackPressedCallback או OnBackInvokedCallback.

קביעת מצב ממשק המשתמש שמאפשר להפעיל ולהשבית כל קריאה חוזרת (callback)

מצב ממשק המשתמש הוא מאפיין שמתאר את ממשק המשתמש. מומלץ לפעול לפי השלבים הכלליים הבאים.

  1. קובעים את מצב ממשק המשתמש שמאפשר להפעיל ולהשבית כל קריאה חוזרת.

  2. מגדירים את המצב באמצעות סוג של מאגר נתונים שניתן לצפייה בו, כמו StateFlow או Compose State, ומפעילים או משביתים את הקריאה החוזרת כשהמצב משתנה.

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

שימוש בהתקשרות חזרה של המערכת ללוגיקה של ממשק המשתמש

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

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

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

  • אפשר להשתמש ב-OnBackInvokedCallback עם PRIORITY_SYSTEM_NAVIGATION_OBSERVER במכשירים עם Android מגרסה 16 ואילך. הפעולה הזו יוצרת observer-callback שלא צורך את אירוע החזרה. לדוגמה, אפשר לרשום את הקריאה החוזרת הזו כשהמשתמש מחליק אחורה מהפעילות הבסיסית, או במילים אחרות, כשהמשתמש יוצא מהאפליקציה. במקרה כזה, אפשר לרשום ביומן את אירוע החזרה או להפעיל לוגיקה עסקית אחרת, והאנימציה של החזרה למסך הבית עדיין תפעל.
  • במקרים של פעילות לפעילות או של קטע לפעילות, מתבצעת רישום ביומן אם isFinishing בתוך onDestroy הוא true בתוך מחזור החיים של הפעילות.
  • במקרים של מעבר מקטע לקטע, מתבצע רישום ביומן אם isRemoving בתוך onDestroy הוא true במהלך מחזור החיים של התצוגה של הקטע. אפשר גם להתחבר באמצעות השיטות onBackStackChangeStarted או onBackStackChangeCommitted בתוך FragmentManager.OnBackStackChangedListener.
  • במקרה של יצירת הודעה, צריך לבצע רישום ביומן בתוך הקריאה החוזרת (callback) onCleared() של ViewModel שמשויך ליעד של יצירת ההודעה. זהו האות הטוב ביותר לדעת מתי יעד של Compose מוצא מהמחסנית האחורית ונהרס.

יצירת קריאות חוזרות עם אחריות יחידה

אפשר להוסיף כמה קריאות חוזרות למרכז הבקשות. הקריאות החוזרות מתווספות למחסנית שבה הקריאה החוזרת האחרונה שנוספה מטפלת בתנועת החזרה הבאה, עם קריאה חוזרת אחת לכל תנועת חזרה.

קל יותר לנהל את מצב ההפעלה של קריאה חוזרת אם לקריאה החוזרת יש אחריות אחת. לדוגמה:

סדר הקריאות החוזרות במחסנית.
איור 2. תרשים של סטאק הקריאות החוזרות.

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

הקריאה החוזרת השנייה יכולה לכלול רכיב Material שתומך בהחזרה ניבויית, מעבר AndroidX באמצעות Progress APIs או קריאה חוזרת מותאמת אישית אחרת.

קריאה חוזרת (callback) של childFragmentManager's מופעלת אם הקריאות החוזרות שלמעלה מושבתות ומחסנית החזרה של FragmentManager הזו לא ריקה, כאשר childFragmentManager מצורף בתוך Fragment. בדוגמה הזו, הקריאה החוזרת הפנימית מושבתת.

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

לבסוף, super.onBackPressed()היא קריאה חוזרת ברמת המערכת, שמופעלת שוב אם הקריאות החוזרות שלמעלה מושבתות. כדי להפעיל אנימציות מערכת כמו חזרה למסך הבית, מעבר בין פעילויות ומעבר בין משימות, מחסנית החזרה של supportFragmentManager צריכה להיות ריקה כדי שהקריאה החוזרת הפנימית שלה תושבת.

בדיקת האנימציה של חיזוי תנועת החזרה

אם אתם עדיין משתמשים ב-Android 13 או ב-Android 14, אתם יכולים לבדוק את האנימציה של החזרה למסך הבית שמוצגת באיור 1.

כדי לבדוק את האנימציה הזו, מבצעים את השלבים הבאים:

  1. במכשיר, עוברים אל הגדרות > מערכת > אפשרויות למפתחים.

  2. בוחרים באפשרות חיזוי אנימציה של תנועת החזרה.

  3. מפעילים את האפליקציה המעודכנת ומשתמשים בתנועת החזרה כדי לראות אותה בפעולה.