בדף הזה מפורטות כמה מהסיבות הנפוצות לכשלים בשירותי חזית, ואנחנו עוזרים לכם לזהות את הגורם לבעיה.
במסמך הזה מפורטות הבעיות הבאות:
לפני פתרון הבעיות
בדיקת שינויים אחרונים בשירותים שפועלים בחזית
אם משתמשים בשירותים שפועלים בחזית בצורה לא נכונה, הם עלולים להשפיע לרעה על הביצועים של המכשיר ועל חיי הסוללה. לכן, גרסאות של פלטפורמת Android כוללות לעיתים קרובות שינויים בהתנהגות של שירותים שפועלים בחזית כדי להגביל את ההשפעות השליליות האלה.
אם נתקלת בבעיות בשירותים בחזית, כדאי לעיין במסמכי העזרה בנושא שינויים בשירותים בחזית ולבדוק אם יש שינויים מהזמן האחרון שעשויים להסביר את הבעיות. חשוב במיוחד לבדוק אם יש שינויים במקרים הבאים:
- קוד של שירות שפועל בחזית שפעל בעבר נכשל עכשיו
- התחלתם לבדוק גרסה חדשה של פלטפורמה או שיניתם את רמת ה-API שאליה האפליקציה שלכם מטרגטת
בנוסף, אם אתם בודקים את המכשיר בגרסה טרום-השקה למפתחים של הפלטפורמה, חשוב לבדוק את הגרסה העדכנית ביותר של מסמכי התיעוד לגרסה טרום-השקה למפתחים.
שגיאות מסוג 'האפליקציה לא מגיבה (ANR)'
בנסיבות מסוימות, אפליקציה אמורה להשבית את השירות שלה בחזית. אם האפליקציה לא תפסיק את השירות, המערכת תפסיק אותו ותגרום לשגיאה מסוג האפליקציה לא מגיבה (ANR).
שירות קצר פועל יותר מדי זמן וגורם ל-ANR
שירותים שפועלים בחזית ומשתמשים בשירות קצר חייבים להשלים את הפעולה במהירות, תוך כשלוש דקות. כשהזמן פג, המערכת מפעילה את השיטה Service.onTimeout(int,int)
של השירות. לשירות יש כמה שניות להתקשר אל stopSelf()
. אם השירות לא יעצור את עצמו, המערכת תפעיל שגיאה מסוג 'האפליקציה לא מגיבה'.
אבחון:
אם אירוע ה-ANR נגרם בגלל ששירות בחזית לא הצליח להפסיק את עצמו, המערכת תשליך חריגה פנימית. כדי לוודא שזו הבעיה, אפשר לבדוק את Logcat. במקרה כזה, יופיע ביומן ההודעה הבאה:
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)
.
חשוב לוודא שההטמעה של השיטה הזו מפעילה את stopSelf()
באופן מיידי.
חריגים לשירותים שפועלים בחזית
בקטע הזה מתוארות כמה בעיות בשירותים בחזית שיכולות לגרום למערכת להוציא חריגה. אם האפליקציה לא תתעד את החריגה, תופיע תיבת דו-שיח עם הודעה על כך שהאפליקציה הופסקה.
במקרים מסוימים, המערכת תיצור חריגה פנימית. אי אפשר לתפוס את החריגות האלה, אבל אפשר לבדוק ב-Logcat איזו חריגה הופיעה.
חריגה פנימית: זמן הקצוב פג
המערכת מטילה מגבלה על משך הזמן שבו שירותי עיבוד מדיה וסנכרון נתונים יכולים לפעול בחזית (foreground) בזמן שהאפליקציה ברקע. אם השירות חורג מהמגבלה הזו, המערכת קוראת לשיטה Service.onTimeout(int,int)
של השירות. לשירות יש כמה שניות להתקשר ל-stopSelf()
. אם השירות לא יעצור את עצמו, המערכת תיצור חריגה פנימית שגורמת לקריסת האפליקציה.
אבחון:
אם הסיבה היא חריגה מזמן הקצאת הזמן, ההודעה הבאה תופיע ב-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)
בשירותים שפועלים בחזית.
חשוב לוודא שההטמעה של השיטה הזו מפעילה את stopSelf()
באופן מיידי.
חריג פנימי: ForegroundServiceDidNotStartInTimeException
כשמפעילים שירות באמצעות קריאה ל-context.startForegroundService()
, לשירות יש כמה שניות לקדם את עצמו לשירות שפועל בחזית באמצעות קריאה ל-ServiceCompat.startForeground()
.
אם השירות לא עושה זאת, המערכת מפעילה שגיאת ANR.
אבחון:
אם שירות שפועל בחזית לא הופעל בזמן, האפליקציה תקרוס והמשתמש יראה את תיבת הדו-שיח האפליקציה הופסקה. במקרה כזה, תוצג ההודעה הבאה ב-Logcat:
android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
Context.startForegroundService() did not then call Service.startForeground()
הפתרון:
חשוב לוודא שכל השירותים החדשים שנוצרו שפועלים בחזית קוראים ל-ServiceCompat.startForeground()
תוך כמה שניות.
ForegroundServiceStartNotAllowedException
שגיאה:
המערכת גורמת להשלכה של ForegroundServiceStartNotAllowedException
.
הסיבה:
בדרך כלל, הסיבה לכך היא שהאפליקציה מפעילה שירות שפועל בחזית מהרקע כשאין פטור תקף.
החל מגרסה Android 12 (רמת API 31), לאפליקציות אסור להפעיל שירותים שפועלים בחזית בזמן שהאפליקציה פועלת ברקע, מלבד כמה חריגים ספציפיים.
אם מנסים להפעיל שירות שפועל בחזית מהרקע ולא עומדים בדרישות של אחת מההחרגות, המערכת תשליך את השגיאה ForegroundServiceStartNotAllowedException
. המערכת עושה זאת גם אם אתם לא עומדים בדרישות לפטור.
לדוגמה, יכול להיות שבאפליקציה יש לחצן שהמשתמש יכול ללחוץ עליו, וכתוצאה מכך האפליקציה מבצעת עיבוד מסוים ואז מפעילה שירות שפועל בחזית. במקרה כזה, יש סכנה שהמשתמש ילחץ על הלחצן ולאחר מכן מיד יעביר את האפליקציה לרקע. במקרה כזה, האפליקציה תנסה להפעיל את השירות מהרקע. אם האפליקציה לא עומדת באחד מהפטורים שצוינו, המערכת תשליך הודעת שגיאה מסוג ForegroundServiceStartNotAllowedException
.
בנוסף, לחלק מהפטורים יש מגבלה זמנית קצרה. לדוגמה, יש פטור קצר אם האפליקציה מפעילה שירות בחזית בתגובה להודעת FCM בעדיפות גבוהה. אם לא תפעילו את השירות במהירות מספקת, יוצג לכם ForegroundServiceStartNotAllowedException
.
לפעמים, כשאנחנו משיקים גרסאות חדשות של Android, ההחרגות הספציפיות הופכות למחמירות יותר. אם שיניתם את גרסת Android שאליה האפליקציה שלכם מטרגטת, כדאי לעיין במסמכים בנושא שינויים בשירותי חזית ולוודא שהאפליקציה עדיין עומדת בקריטריונים של אחת מהפטרונות המותרים.
הפתרון:
לשנות את תהליך העבודה של האפליקציה כך שלא יהיה צורך להפעיל שירותים בחזית בזמן שהאפליקציה פועלת ברקע, או לוודא שהאפליקציה עומדת באחד מהפטורים.
אתם יכולים להשתמש ברכיבי מחזור חיים כמו LiveData
כדי לנהל את מחזור החיים של האפליקציה, וכך למנוע ניסיון לא מכוון להפעיל שירות שפועל בחזית מהרקע.
SecurityException
שגיאה:
המערכת תיצור את ההודעהSecurityException
.
הסיבה:
האפליקציה ניסתה להפעיל שירות שפועל בחזית בלי ההרשאות הנדרשות.
- אם אפליקציה מטרגטת ל-Android 9 (רמת API 28) ואילך, היא צריכה את ההרשאה
FOREGROUND_SERVICE
כדי להפעיל שירות שפועל בחזית. - אם אפליקציה מטרגטת ל-Android 14 (רמת API 34) ואילך, היא צריכה לעמוד בכל הדרישות המוקדמות לסוג השירות שפועל בחזית שלה. הדרישות המקדימות האלה מפורטות במאמר העזרה בנושא סוגים של שירותים שפועלים בחזית. חשוב לשים לב במיוחד לדרישות הבאות:
- יש כמה סוגים של שירותים שפועלים בחזית שדורשים הרשאות ספציפיות בסביבת זמן הריצה. לדוגמה, לשירות שפועל בחזית להעברת הודעות מרחוק צריכה להיות ההרשאה
FOREGROUND_SERVICE_REMOTE_MESSAGING
.
- יש כמה סוגים של שירותים שפועלים בחזית שדורשים הרשאות ספציפיות בסביבת זמן הריצה. לדוגמה, לשירות שפועל בחזית להעברת הודעות מרחוק צריכה להיות ההרשאה
- במקרים מסוימים, יש הגבלות נוספות בזמן השימוש לגבי ההרשאות שנדרשות לסוגים מסוימים של שירותים שפועלים בחזית. ההרשאות האלה מוענקות לאפליקציה רק כשהיא בחזית (למעט כמה יוצאי דופן ספציפיים). כלומר, גם אם האפליקציה ביקשה אחת מההרשאות האלה וקיבלתם אותה, אם האפליקציה תנסה להפעיל את השירות שפועל בחזית בזמן שהיא ברקע, המערכת תשליך הודעת
SecurityException
גם אם לאפליקציה יש פטור להפעלת שירות שפועל בחזית מהרקע. מידע נוסף זמין במאמר הגבלות על הפעלת שירותים שפועלים בחזית שצריכים הרשאות לשימוש.- יכול להיות שתקבלו את הערך
SecurityException
אם ביקשת את ההרשאות הנדרשות אבל הפעלת את השירות בחזית לפני שמוודאים שההרשאות הנדרשות אושרו.
- יכול להיות שתקבלו את הערך
הפתרון:
לפני שמפעילים את השירות שפועל בחזית, צריך לבקש את כל ההרשאות המתאימות לשירות שפועל בחזית, ולוודא שעמדתם בכל שאר הדרישות המוקדמות בסביבת זמן הריצה.