כשאפליקציה פועלת ברקע, היא צורכת חלק מהמשאבים המוגבלים של המכשיר, כמו זיכרון RAM. כתוצאה מכך, חוויית המשתמש עלולה להיפגע, במיוחד אם המשתמש משתמש באפליקציה שמחייבת הרבה משאבים, כמו משחק או צפייה בסרטון. כדי לשפר את חוויית המשתמש, ב-Android 8.0 (רמת API 26) יש הגבלות על הפעולות שהאפליקציות יכולות לבצע כשהן פועלות ברקע. במסמך הזה מתוארים השינויים במערכת ההפעלה ואיך אפשר לעדכן את האפליקציה כך שתעבוד בצורה תקינה במסגרת המגבלות החדשות.
סקירה כללית
אפשר להפעיל בו-זמנית אפליקציות ושירותים רבים ב-Android. לדוגמה, משתמש יכול לשחק במשחק בחלון אחד, לגלוש באינטרנט בחלון אחר ולהשתמש באפליקציה שלישית כדי להפעיל מוזיקה. ככל שיותר אפליקציות פועלות בו-זמנית, כך עומס העבודה על המערכת גדל. אם אפליקציות או שירותים נוספים פועלים ברקע, המערכת נאלצת להתמודד עם עומסי עבודה נוספים, וכתוצאה מכך חוויית המשתמש עלולה להיפגע. לדוגמה, יכול להיות שאפליקציית המוזיקה תיסגר באופן פתאומי.
כדי לצמצם את הסיכוי לבעיות כאלה, ב-Android 8.0 יש הגבלות על הפעולות שאפשר לבצע באפליקציות כשהמשתמשים לא מבצעים אינטראקציה ישירה איתן. יש שתי דרכים להגביל אפליקציות:
הגבלות על שירותי רקע: כשאפליקציה לא פעילה, יש הגבלות על השימוש שלה בשירותי רקע. הדבר לא חל על שירותים בחזית, שגלויים יותר למשתמש.
הגבלות שידור: עם חריגים מוגבלים, אפליקציות לא יכולות להשתמש במניפסט שלהן כדי להירשם לשידורים משתמעים. הם עדיין יכולים להירשם לשידורים האלה בזמן הריצה, והם יכולים להשתמש במניפסט כדי להירשם לשידורים בוטהים ולשידורים שמטורגטים במיוחד לאפליקציה שלהם.
ברוב המקרים, אפשר לעקוף את המגבלות האלה באמצעות משימות JobScheduler
. הגישה הזו מאפשרת לאפליקציה לבצע משימות כשהיא לא פועלת באופן פעיל, אבל עדיין נותנת למערכת את הגמישות לתזמן את המשימות האלה באופן שלא משפיע על חוויית המשתמש. ב-Android 8.0 יש כמה שיפורים ב-JobScheduler
שמאפשרים להחליף שירותים ומקלטים לשידור עם משימות מתוזמנות בקלות רבה יותר. מידע נוסף זמין במאמר שיפורים ב-JobScheduler.
הגבלות על שירותים שפועלים ברקע
שירותים שפועלים ברקע יכולים לנצל משאבי המכשיר, וכתוצאה מכך חוויית המשתמש עלולה להיפגע. כדי לצמצם את הבעיה הזו, המערכת מחילה מספר הגבלות על השירותים.
המערכת מבדילה בין אפליקציות בחזית לבין אפליקציות ברקע. (ההגדרה של 'רקע' לצורכי הגבלות שירות שונה מההגדרה שמשמשת לניהול זיכרון. אפליקציה עשויה להיות ברקע מבחינת ניהול הזיכרון, אבל בחזית מבחינת היכולת שלה להפעיל שירותים). אפליקציה נחשבת כאפליקציה בחזית אם מתקיים אחד מהתנאים הבאים:
- יש לו פעילות גלויה, גם אם הפעילות מופעלת וגם אם היא מושהית.
- יש לה שירות שפועל בחזית.
- אפליקציה אחרת בחזית מחוברת לאפליקציה, באמצעות קישור לאחד מהשירותים שלה או באמצעות שימוש באחד מספקי התוכן שלה. לדוגמה, האפליקציה נמצאת בחזית אם אפליקציה אחרת מקשרת אליה את:
- IME
- שירות טפטים
- מאזין להתראות
- שירות קולי או שירות שליחת הודעות
אם אף אחד מהתנאים האלה לא מתקיים, האפליקציה נחשבת כפעילה ברקע.
כשאפליקציה פועלת בחזית, היא יכולה ליצור ולהפעיל שירותים שפועלים בחזית וברקע באופן חופשי. כשאפליקציה עוברת לרקע, יש לה חלון של כמה דקות שבו היא עדיין יכולה ליצור שירותים ולהשתמש בהם. בסוף החלון הזה, האפליקציה נחשבת ללא פעילה. בשלב הזה, המערכת מפסיקת את שירותי הרקע של האפליקציה, בדיוק כמו שהאפליקציה הייתה מפעילה את השיטות Service.stopSelf()
של השירותים.
בנסיבות מסוימות, אפליקציה שפועלת ברקע מועברת לרשימת ההיתרים הזמנית למשך כמה דקות. כשאפליקציה נמצאת ברשימת ההיתרים, היא יכולה להפעיל שירותים ללא הגבלה, ושירותי הרקע שלה מורשים לפעול. אפליקציה מתווספת לרשימת ההיתרים כשהיא מטפלת במשימה שגלויה למשתמש, למשל:
- טיפול בהודעה בעדיפות גבוהה מ-Firebase Cloud Messaging (FCM).
- קבלת שידור, כמו הודעת SMS/MMS.
- ביצוע
PendingIntent
מהתראה. - הפעלת
VpnService
לפני שאפליקציית ה-VPN מעבירה את עצמה לחזית.
במקרים רבים, האפליקציה יכולה להחליף שירותי רקע במשימות של JobScheduler
.
לדוגמה, אפליקציית CoolPhotoApp צריכה לבדוק אם המשתמש קיבל תמונות משותפות מחברים, גם אם האפליקציה לא פועלת בחזית. בעבר, האפליקציה השתמשה בשירות רקע שבדק את האחסון בענן של האפליקציה. כדי לעבור ל-Android 8.0 (רמת API 26), המפתח מחליף את שירות הרקע במשימה מתוזמנת. המשימה מופעלת מדי פעם, שולחת שאילתה לשרת ואז יוצאת.
לפני Android 8.0, הדרך הרגילה ליצור שירות שפועל בחזית הייתה ליצור שירות ברקע ואז להעביר את השירות הזה לחזית.
ב-Android 8.0 יש בעיה: המערכת לא מאפשרת לאפליקציה שפועלת ברקע ליצור שירות ברקע. לכן, ב-Android 8.0 מופיעה השיטה החדשה startForegroundService()
להפעלת שירות חדש בחזית. אחרי שהמערכת יוצרת את השירות, לאפליקציה יש חמש שניות כדי להפעיל את השיטה [startForeground()
](/reference/android/app/Service#startForeground(int, android.app.Notification) של השירות כדי להציג את ההתראה של השירות החדש שגלויה למשתמשים. אם האפליקציה לא קוראת ל-startForeground()
במסגרת המגבלה הזמן, המערכת תפסיק את השירות ותכריז על האפליקציה כANR.
הגבלות על שידור
אם אפליקציה נרשמת לקבלת שידורים, מקלט האפליקציה צורך משאבים בכל פעם שהשידור נשלח. הדבר עלול לגרום לבעיות אם יותר מדי אפליקציות נרשמות לקבלת שידורים על סמך אירועי מערכת. אירוע מערכת שמפעיל שידור יכול לגרום לכל האפליקציות האלה לצרוך משאבים ברצף מהיר, וכך לפגוע בחוויית המשתמש. כדי לצמצם את הבעיה הזו, ב-Android 7.0 (רמת API 24) הוגדרו מגבלות על שידורים, כפי שמתואר בקטע אופטימיזציה לרקע. מגבלות אלה מחמירות יותר ב-Android 8.0 (רמת API 26).
- אפליקציות שמטרגטות ל-Android מגרסה 8.0 ואילך לא יכולות יותר לרשום במניפסט שלהן מקלט שידור לשידורים משתמעים, אלא אם השידור מוגבל לאפליקציה הזו באופן ספציפי. שידור משתמע הוא שידור שלא מטרגט רכיב ספציפי באפליקציה. לדוגמה,
ACTION_PACKAGE_REPLACED
נשלח לכל המאזינים הרשומים בכל האפליקציות, כדי להודיע להם שחבילה כלשהי במכשיר הוחלפה. מכיוון שהשידור הוא משתמע, הוא לא יועבר למקלטים שרשומים במניפסט באפליקציות שמטרגטות Android מגרסה 8.0 ואילך.ACTION_MY_PACKAGE_REPLACED
גם הוא שידור משתמע, אבל מכיוון שהוא נשלח רק לאפליקציה שהחבילה שלה הוחלפה, הוא יועבר לנמענים שרשומים במניפסט. - אפליקציות יכולות להמשיך להירשם לשידורים בעלי תוכן בוטה במניפסטים שלהן.
- אפליקציות יכולות להשתמש ב-
Context.registerReceiver()
בסביבת זמן הריצה כדי לרשום מקלט לכל שידור, בין אם הוא משתמע ובין אם הוא מפורש. - שידורים שדורשים הרשאת חתימה פטורים מההגבלה הזו, כי השידורים האלה נשלחים רק לאפליקציות שנחתמו באותו אישור, ולא לכל האפליקציות במכשיר.
במקרים רבים, אפליקציות שנרשמו בעבר לשידור משתמע יכולות לקבל פונקציונליות דומה באמצעות משימה מסוג JobScheduler
.
לדוגמה, יכול להיות שאפליקציית תמונות של רשת חברתית תצטרך לנקות את הנתונים שלה מדי פעם, והיא מעדיפה לעשות זאת כשהמכשיר מחובר למטען.
בעבר, האפליקציה רשמה מקלט ל-ACTION_POWER_CONNECTED
במניפסט שלה. כשהאפליקציה קיבלה את השידור הזה, היא בדקה אם יש צורך בניקוי. כדי לעבור ל-Android 8.0 ואילך, האפליקציה מסירה את המקלט הזה מהמניפסט שלה. במקום זאת, האפליקציה מתזמנת משימה לניקוי שמריצים כשהמכשיר במצב מנוחה ובטעינה.
מדריך להעברת נתונים (מיגרציה)
כברירת מחדל, השינויים האלה משפיעים רק על אפליקציות שמטרגטות ל-Android 8.0 (רמת API 26) ואילך. עם זאת, משתמשים יכולים להפעיל את ההגבלות האלה לכל אפליקציה במסך הגדרות, גם אם האפליקציה מטרגטת לרמת API נמוכה מ-26. יכול להיות שתצטרכו לעדכן את האפליקציה כדי לעמוד במגבלות החדשות.
בודקים איך האפליקציה משתמשת בשירותים. אם האפליקציה שלכם מסתמכת על שירותים שפועלים ברקע בזמן שהאפליקציה לא פעילה, תצטרכו להחליף אותם. פתרונות אפשריים:
- אם האפליקציה צריכה ליצור שירות שפועל בחזית בזמן שהיא פועלת ברקע, צריך להשתמש בשיטה
startForegroundService()
במקום ב-startService()
. - אם המשתמש יכול לראות את השירות, צריך להגדיר אותו כשירות שפועל בחזית. לדוגמה, שירות שמפעיל אודיו צריך תמיד להיות שירות שפועל בחזית.
יוצרים את השירות באמצעות השיטה
startForegroundService()
במקוםstartService()
. - מוצאים דרך לשכפל את הפונקציונליות של השירות באמצעות משימה מתוזמנת. אם השירות לא מבצע פעולה שגלויה למשתמש באופן מיידי, בדרך כלל אפשר להשתמש במקום זאת במשימה מתוזמנת.
- כדאי להשתמש ב-FCM כדי להעיר את האפליקציה באופן סלקטיבי כשמתרחשים אירועי רשת, במקום לבצע סקרים ברקע.
- כדאי לדחות את עבודת הרקע עד שהאפליקציה תהיה בחזית באופן טבעי.
בודקים את מקלטי השידור שהוגדרו במניפסט של האפליקציה. אם המניפסט מצהיר על מקלט לשידור משתמע מושפע, צריך להחליף אותו. פתרונות אפשריים:
- יוצרים את המקלט בזמן הריצה באמצעות קריאה ל-
Context.registerReceiver()
, במקום להצהיר על המקלט במניפסט. - משתמשים במשימה מתוזמנת כדי לבדוק את התנאי שהיה מפעיל את השידור המשתמע.