ב-Android 9 (וגרסאות קודמות), אפליקציות הועברו למצב PAUSED
כאשר:
- פעילות חדשה שקופה הופיעה מעל האפליקציה בזמן שהאפליקציה עדיין הייתה גלויה (ולכן לא הופסקה).
- הפעילות אבדה, אבל היא לא הייתה מוסתרת וייתכן למשתמש הייתה אינטראקציה איתה. לדוגמה, במצב ריבוי חלונות, ניתן לראות מספר פעילויות ולקבל קלט מגע בו-זמנית.
המצבים האלה שונים במספר ההשהיות שהאפליקציה צריכה לבצע, אבל אי אפשר להבדיל ביניהם ברמת האפליקציה.
ב-Android 10, כל הפעילויות שאפשר להתמקד בהן בראש הערימות הגלויות נמצאות במצב RESUMED
. כך אפשר לשפר את התאימות למצב 'חלונות מרובים' ולמצב MD באפליקציות שמשתמשות ב-onPause()
במקום ב-onStop()
כדי להפסיק את הרענון של ממשק המשתמש ואת האינטראקציה עם המשתמש. מה זה אומר?
- שתי הפעילויות במסך המפוצל ממשיכות.
- כל הפעילויות שמוצגות בחלק העליון של המסך במצב חלונות בפורמט חופשי ימשיכו לפעול.
- אפשר להמשיך פעילויות בכמה מסכים בו-זמנית.
איור 1. המשך של כמה פעילויות במכשיר מתקפל
איור 2. המשך של כמה משימות בו-זמנית במצב שולחן עבודה
פעילויות יכולות להיות במצב PAUSED
כשאי אפשר להתמקד בהן או שהן מוסתרות חלקית, למשל:
- במסך מפוצל בקטן (עם מרכז האפליקציות בצד), הפעילות העליונה לא תתחדש כי אי אפשר להתמקד בה.
- במצב'תמונה בתוך תמונה', הפעילות לא תתחדש כי אי אפשר להתמקד בה.
- פעילויות שמכסות פעילויות שקופות אחרות באותה מקבץ.
הגישה הזו מציינת לאפליקציות שפעילות יכולה לקבל קלט ממשתמש רק במצב RESUMED
. לפני Android 10, פעילויות יכלו לקבל קלט גם במצב PAUSED
(לדוגמה, נסו לגעת בשתי הפעילויות במסך מפוצל בו-זמנית במכשיר עם Android 9).
כדי לשמור על האות resumed מהגרסאות הקודמות של Android (ולתקשר מתי אפליקציות צריכות לקבל גישה למשאבים עם גישה בלעדית או למשאבים מסוג singleton), מערכת Android 10 כוללת קריאה חוזרת חדשה:
Activity#onTopResumedActivityChanged(boolean onTop)
כשהיא מופעלת, הקריאה החוזרת הזו מתבצעת בין Activity#onResume()
ל-Activity#onPause()
. הקריאה החוזרת הזו היא אופציונלית וניתן לדלג עליה, כך שפעילות יכולה לעבור ממצב RESUMED
למצב PAUSED
בלי להפוך לפעילות העליונה במערכת. לדוגמה, במצב ריבוי חלונות.
הקריאה החוזרת הזו היא אופציונלית, ולכן היא לא חלק ממחזור החיים של הפעילות, ומומלץ להשתמש בה לעיתים רחוקות.
הפעילות הקודמת בראש הרשימה של הפעילויות שהושעו מחדש מקבלת את onTopResumedActivity(false)
ומסיימת את הביצוע שלה לפני שהפעילות הבאה ברשימה מקבלת את onTopResumedActivity(true)
, אלא אם הפעילות הקודמת נמשכת יותר מדי זמן כדי לטפל בקריאה ל-method ומגיעה לזמן הקצוב של 500 אלפיות השנייה.
תאימות
כדי לשמור על תאימות כשמטמיעים כמה קורות חיים, כדאי לשקול את הפתרונות הבאים.
מספר פעילויות שהושעו בתהליך אפליקציה אחד
- בעיה. ב-Android 9 ומטה, רק פעילות אחת במערכת מתחדשת בכל פעם. כל המעברים בין פעילויות כוללים השהיה של פעילות לפני שממשיכים פעילות אחרת. אפליקציות ופלטפורמות מסוימות (כמו Flutter או LocalActivityManager של Android) משתמשות בעובדה הזו ומאחסנות את המצב של הפעילות שהמשיכה ב-singletons.
- פתרון. ב-Android מגרסה 9 ואילך, אם שתי פעילויות מאותו תהליך מופעלות מחדש, המערכת ממשיכה רק את הפעילות שמדורגת גבוה יותר בסדר Z. אפליקציות שמטורגטות ל-Android 10 יכולות לתמוך בהמשך של כמה פעילויות בו-זמנית.
גישה בו-זמנית למצלמה
- בעיות. הבעיות האלה קיימות גם ב-Android מגרסה 9 ואילך. לדוגמה, פעילות במסך מלא שהופעלה מחדש עשויה לאבד את המיקוד של המצלמה לפעילות מושהית שמופיעה בחלק העליון במצב 'תמונה בתוך תמונה', אבל היא עשויה להיות חשופה יותר ככל שיותר משתמשים יעברו למצבים של ריבוי חלונות וריבוי מסכים.
- בגלל שינויים שבוצעו במצב
RESUME
, יכול להיות שאפליקציות ינותקו מהמצלמה גם במהלך המשך. כדי לפתור את הבעיה, האפליקציות צריכות לטפל בניתוק של המצלמה בלי לקרוס. כשהחיבור מנותק, האפליקציות מקבלות קריאה חוזרת (callback) ללא חיבור וכל הקריאות ל-API מתחילות להוציא את השגיאהCameraAccessException
. resizeableActivity=false
לא מבטיח גישה בלעדית למצלמה, כי אפשר לפתוח אפליקציות אחרות שמשתמשות במצלמה במסכים אחרים.
- בגלל שינויים שבוצעו במצב
- פתרונות מפתחים צריכים לכלול לוגיקה למקרה שבו אפליקציה מנותקת מהמצלמה. אם אפליקציה מנותקת מהמצלמה, היא צריכה לעקוב אחרי קריאות חזרה לגבי זמינות המצלמה כדי לנסות להתחבר מחדש ולהמשיך להשתמש במצלמה. בנוסף להודעת החזרה (callback) הקיימת
CameraManager#AvailabilityCallback#onCameraAvailable()
, ב-Android 10 נוספהCameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged()
, שמתאימה למקרה שבו המיקוד (ועדיפות המצלמה) עוברים בין כמה פעילויות שהושעו. מפתחי אפליקציות צריכים להשתמש בשני פונקציות ה-callbacks האלה כדי לקבוע מתי כדאי לנסות לקבל גישה למצלמה.
חזרה להקראה בכמה קטעים
ב-Android 10, מצב מחזור החיים של הפעילות נקבע לפי ההצגה וסדר Z. כדי לוודא שהמצב הנכון אחרי עדכוני החשיפה בפעילות הוא המצב המתאים, ולבדוק איזה מצב מחזור חיים רלוונטי, צריך להפעיל את השיטה ActivityRecord#makeActiveIfNeeded()
ממיקומים שונים. ב-Android 10, הערך 'פעיל' הוא RESUMED
או PAUSED
, והוא פועל רק בשני המקרים האלה.
ב-Android 10, המעקב אחרי חזרה לפעילות מתבצע בנפרד בכל סטאק, במקום במיקום יחיד במערכת. הסיבה לכך היא שאפשר לבצע כמה מעברים בין פעילויות בו-זמנית במצבים עם כמה חלונות. מידע נוסף זמין בקטע ActivityStack#mInResumeTopActivity
.
קריאה חוזרת לפעילות שהושבתה הכי הרבה פעמים
אחרי פעולות שעשויות לגרום לשינוי בפעילות העליונה (כמו הפעלה של פעילות, המשך פעילות או שינוי בסדר Z), מתבצעת קריאה ל-ActivityStackSupervisor#updateTopResumedActivityIfNeeded()
. השיטה הזו בודקת אם הפעילות בחלק העליון שחוזרת על עצמה השתנתה, ומבצעת את העדכון במקרה הצורך. אם הפעילות הקודמת בעדיפות הגבוהה ביותר להמשך לא שחררה את המצב בעדיפות הגבוהה ביותר להמשך, נשלחת אליה הודעה על אובדן המצב בעדיפות הגבוהה ביותר להמשך, ומתוזמן זמן קצוב לתפוגה בצד השרת (ActivityStackSupervisor#scheduleTopResumedStateLossTimeout()
). דוח של המצב בעדיפות הגבוהה ביותר להמשך נשלח לפעילות הבאה אחרי שהפעילות הקודמת שחררה את המצב, או כשהזמן הקצוב לתפוגה פג (ראו שימושים ב-:
ActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()
נוסף פריט עסקה חדש מסוג TopResumedActivityChangeItem
כדי לדווח ללקוחות על שינויים במצב של ההמשך העליון, והוא משתמש בארכיטקטורה של ActivityLifecycler
מ-Android 9.
המצב של ההמשך העליון נשמר בצד הלקוח, וכל פעם שהפעילות עוברת ל-RESUMED
או ל-PAUSED
, היא גם בודקת אם צריך להפעיל את הפונקציה החוזרת onTopResumedActivityChanged()
. כך אפשר לבצע ניתוק מסוים בתקשורת של מצבי מחזור החיים ושל המצב 'המשך מהמצב העליון' בין הצד של השרת לצד של הלקוח.