בדף הזה מפורטות כמה סיבות נפוצות לכך ששירותים שפועלים בחזית נכשלים, ומוסבר איך לזהות את הגורם לבעיה.
במסמך הזה מפורטות הבעיות הבאות:
לפני שמתחילים לפתור את הבעיה
בדיקת השינויים שבוצעו לאחרונה בשירותים שפועלים בחזית
אם משתמשים בשירותים שפועלים בחזית בצורה לא נכונה, הם יכולים להשפיע לרעה על הביצועים של המכשיר ועל חיי הסוללה. לכן, בגרסאות של פלטפורמת Android לעיתים קרובות יש שינויים בהתנהגות של שירותים שפועלים בחזית כדי להגביל את ההשפעות השליליות האלה.
אם נתקלתם בבעיות בשירותים שפועלים בחזית, כדאי לעיין במסמכי התיעוד בנושא השינויים בשירותים שפועלים בחזית ולבדוק אם יש שינויים שבוצעו לאחרונה שיכולים להסביר את הבעיות. חשוב במיוחד לבדוק אם יש שינויים במקרים הבאים:
- קוד של שירות שפועל בחזית שפעל בעבר נכשל עכשיו
- התחלתם לבדוק גרסה חדשה של הפלטפורמה, או ששיניתם את רמת ה-API שהאפליקציה מטרגטת.
בנוסף, אם אתם בודקים את המכשיר בגרסת תצוגה מקדימה למפתחים של הפלטפורמה, חשוב לבדוק את הגרסה העדכנית ביותר של המסמכים של גרסת תצוגה מקדימה למפתחים.
שגיאות מסוג "האפליקציה לא מגיבה" (ANR)
בנסיבות מסוימות, האפליקציה אמורה לסגור את השירות שפועל בחזית. אם האפליקציה לא עוצרת את השירות, המערכת עוצרת אותו ומפעילה שגיאת האפליקציה לא מגיבה (ANR).
שירות קצר פועל יותר מדי זמן וגורם ל-ANR
שירותים שפועלים בחזית מסוג שירות קצר צריכים להסתיים מהר, תוך כשלוש דקות. כשהזמן נגמר, המערכת קוראת ל-method Service.onTimeout(int,int) של השירות. לשירות יש כמה שניות לקרוא ל-stopSelf(). אם השירות לא מפסיק את עצמו, המערכת מפעילה שגיאת "האפליקציה לא מגיבה".
אבחון:
אם שגיאת ה-ANR נגרמה בגלל ששירות שפועל בחזית לא הפסיק את עצמו, המערכת תציג חריגה פנימית. כדי לוודא שזו הבעיה, אפשר לבדוק את דוחות ה-ANR. אם זו הבעיה, הדוח יכלול את ההודעה הבאה:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type FOREGROUND_SERVICE_TYPE_SHORT_SERVICE did not stop within its timeout:
[component name]"
הפתרון:
חשוב לוודא שכל השירותים שפועלים בחזית ומוגבלים בזמן מסיימים את העבודה שלהם וקוראים ל-stopForeground(int) במסגרת מגבלת הזמן של המערכת.
השירותים שפועלים בחזית צריכים להטמיע את Service.onTimeout(int,int).
חשוב לוודא שההטמעה של ה-method הזה מפעילה את stopSelf() באופן מיידי.
חריגים לשירותים שפועלים בחזית
בקטע הזה מתוארות כמה בעיות בשירות שפועל בחזית שיכולות לגרום למערכת להקפיץ חריגה. אם האפליקציה לא תופסת את החריגה, המשתמש רואה תיבת דו-שיח שמודיעה לו שהאפליקציה הפסיקה לפעול.
במקרים מסוימים, המערכת מחזירה חריגה פנימית. במקרים כאלה, אפשר לברר מה היה החריג על ידי חיפוש בדוח הקריסות, ואפשר לבדוק ב-Logcat כדי לקבל מידע מפורט יותר על השגיאה.
חריגה פנימית: חריגה מהזמן הקצוב
המערכת מגבילה את משך הזמן שבו שירותים שפועלים בחזית לסנכרון נתונים ולעיבוד מדיה יכולים לפעול כשהאפליקציה ברקע. אם השירות חורג מהמגבלה הזו, המערכת קוראת ל-method Service.onTimeout(int,int) של השירות. לשירות יש כמה שניות לקרוא ל-stopSelf(). אם השירות לא מפסיק את עצמו, המערכת יוצרת RemoteServiceException פנימי שגורם לאפליקציה לקרוס.
אבחון:
כדי לגלות מה היה החריג, אפשר לעיין בדוח הקריסות. אפשר גם לבדוק ב-Logcat אם יש מידע מפורט יותר על השגיאה. במקרה כזה, הודעת השגיאה הבאה מופיעה ב-Logcat:
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type [service type] did not stop within its timeout: [component name]"
הפתרון:
חשוב לוודא שכל השירותים שפועלים בחזית ומוגבלים בזמן מסיימים את הפעולה שלהם וקוראים ל-stopForeground(int) במסגרת מגבלת הזמן של המערכת.
השירותים שפועלים בחזית צריכים להטמיע את Service.onTimeout(int,int).
חשוב לוודא שההטמעה של ה-method הזה מפעילה את stopSelf() באופן מיידי.
חריגה פנימית: ForegroundServiceDidNotStartInTimeException
כשמפעילים שירות באמצעות קריאה ל-context.startForegroundService(), לשירות הזה יש כמה שניות לקדם את עצמו לשירות שפועל בחזית באמצעות קריאה ל-ServiceCompat.startForeground().
אם השירות לא עושה זאת, הוא מחזיר שגיאה פנימית ForegroundServiceDidNotStartInTimeException.
אבחון:
כדי לגלות מה היה החריג, אפשר לעיין בדוח הקריסות. אפשר גם לבדוק ב-Logcat אם יש מידע מפורט יותר על השגיאה. במקרה כזה, הודעת השגיאה הבאה מופיעה ב-Logcat:
android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
Context.startForegroundService() did not then call Service.startForeground()
הפתרון:
חשוב לוודא שכל השירותים החדשים שפועלים בחזית קוראים ל-ServiceCompat.startForeground() תוך כמה שניות.
WorkManager:
יכול להיות שתראו את החריגה הזו גם עם קורוטינות WorkManager שמפעילות שירות בחזית (קוראות ל-setForegound או ל-setForegroundAsync). כשמחזור החיים של שתי קורוטינות בחזית חופף, כי קורוטינה אחת מנסה להפעיל שירות בחזית בזמן ששירות בחזית שהופעל קודם מנסה להיסגר, הקריסה הזו תלווה ביומן הבא:
Re-initializing SystemForegroundService after a request to shut-down
תיקון לקריסה הזו נוסף ב-WorkManager גרסה 2.10.5.
אם באפליקציה שלכם מופיעה החריגה הזו, צריך לעדכן לגרסה העדכנית ביותר של WorkManager ולדווח על בעיות שלא נפתרו בIssue Tracker של WorkManager.
ForegroundServiceStartNotAllowedException
שגיאה:
המערכת מציגה את השגיאה ForegroundServiceStartNotAllowedException.
הסיבה:
בדרך כלל זה קורה כשהאפליקציה מפעילה שירות שפועל בחזית מהרקע, ואין פטור תקף.
החל מ-Android 12 (רמת API 31), אפליקציות לא יכולות להפעיל שירותים בחזית כשהן פועלות ברקע, למעט כמה מקרים חריגים ספציפיים.
אם תנסו להפעיל מהרקע שירות שפועל בחזית, ולא תעמדו בדרישות של אחד מהפטורים, המערכת תציג את השגיאה ForegroundServiceStartNotAllowedException. המערכת תעשה את זה גם אם אתם לא עומדים בדרישות לקבלת הפטור.
לדוגמה, יכול להיות שבאפליקציה יש כפתור שהמשתמש יכול ללחוץ עליו, ובעקבות זאת האפליקציה מבצעת עיבוד מסוים ואז מפעילה שירות שפועל בחזית. במקרה כזה, יש סכנה שהמשתמש ילחץ על הכפתור ואז מיד יעביר את האפליקציה לרקע. לאחר מכן, האפליקציה תנסה להפעיל את השירות מהרקע. אם האפליקציה לא עומדת באחד מהפטורים שצוינו, המערכת תציג את השגיאה ForegroundServiceStartNotAllowedException.
בנוסף, חלק מהפטורים מוגבלים בזמן. לדוגמה, יש פטור קצר אם האפליקציה מפעילה שירות שפועל בחזית בתגובה להודעת FCM בעדיפות גבוהה. אם לא מפעילים את השירות מספיק מהר, מקבלים את השגיאה ForegroundServiceStartNotAllowedException.
לפעמים, בגרסאות חדשות של Android, החרגות ספציפיות הופכות למגבילות יותר. אם שיניתם את גרסת Android שהאפליקציה מטרגטת, עיינו במסמכי התיעוד בנושא שינויים בשירותים שפועלים בחזית וודאו שהאפליקציה עדיין עומדת באחד מהפטורים המותרים.
הפתרון:
לשנות את תהליך העבודה של האפליקציה כך שלא יהיה צורך להפעיל שירותים שפועלים בחזית כשהאפליקציה פועלת ברקע, או לוודא שהאפליקציה עומדת באחד מהתנאים לפטור.
אתם יכולים להשתמש ברכיבים שמודעים למחזור החיים כדי לנהל את מחזור החיים של האפליקציה, וכך לא תנסו בטעות להפעיל שירות שפועל בחזית מהרקע.
SecurityException
שגיאה:
המערכת מציגה את השגיאה SecurityException.
הסיבה:
האפליקציה ניסתה להפעיל שירות שפועל בחזית בלי ההרשאות הנדרשות.
- אם האפליקציה מטרגטת ל-Android 9 (רמת API 28) ומעלה, צריכה להיות לה ההרשאה
FOREGROUND_SERVICEכדי להפעיל שירות שפועל בחזית. - אם האפליקציה מטרגטת את Android 14 (רמת API 34) ומעלה, היא צריכה לעמוד בכל הדרישות המוקדמות של סוג השירות שפועל בחזית. הדרישות המוקדמות האלה מפורטות במסמכי התיעוד של סוגי השירותים שפועלים בחזית. חשוב לשים לב במיוחד לדרישות הבאות:
- כדי להשתמש בכמה סוגים של שירותים שפועלים בחזית, צריך הרשאות ספציפיות בתחילת ההפעלה. לדוגמה, שירות שפועל בחזית להעברת הודעות מרחוק חייב לכלול את ההרשאה
FOREGROUND_SERVICE_REMOTE_MESSAGING.
- כדי להשתמש בכמה סוגים של שירותים שפועלים בחזית, צריך הרשאות ספציפיות בתחילת ההפעלה. לדוגמה, שירות שפועל בחזית להעברת הודעות מרחוק חייב לכלול את ההרשאה
- במקרים מסוימים, יש הגבלות נוספות על הרשאות שנדרשות לסוגים מסוימים של שירותים שפועלים בחזית, כשהאפליקציה בשימוש. ההרשאות האלה ניתנות לאפליקציה רק כשהיא פועלת בחזית (עם כמה חריגים ספציפיים). כלומר, גם אם האפליקציה ביקשה וקיבלה את אחת מההרשאות האלה, אם היא תנסה להפעיל את השירות שפועל בחזית בזמן שהיא פועלת ברקע, המערכת תציג
SecurityExceptionגם אם לאפליקציה יש פטור שמאפשר לה להפעיל שירות שפועל בחזית מהרקע. מידע נוסף זמין במאמר הגבלות על הפעלת שירותים שפועלים בחזית ודורשים הרשאות לזמן השימוש.- יכול להיות שתקבלו
SecurityExceptionאם ביקשתם את ההרשאות הנדרשות, אבל הפעלתם את השירות שפועל בחזית לפני שווידאתם שההרשאות הנדרשות ניתנו.
- יכול להיות שתקבלו
הפתרון:
לפני שמפעילים את השירות שפועל בחזית, צריך לבקש את כל ההרשאות המתאימות לשירות שפועל בחזית, ולוודא שעומדים בכל שאר הדרישות המוקדמות של זמן הריצה.