תהליכים ברקע עשויים להעמיס על הזיכרון והסוללה. לדוגמה, שידור מרומז עלולים להתחיל תהליכים רבים שנרשמו ברקע להאזין להם, גם אם התהליכים האלה לא עוזרים לנו. זה יכול לכלול משפיעה משמעותית על ביצועי המכשיר וגם על חוויית המשתמש.
כדי לפתור את הבעיה הזו, מערכת Android 7.0 (רמת API 24) מחילה את הדברים הבאים הגבלות:
- אפליקציות שמטרגטות ל-Android 7.0 (רמת API 24) ואילך לא מקבלות
CONNECTIVITY_ACTION
ישודרו, אם הם להצהיר על מקלט השידור שלהם במניפסט. האפליקציות עדיין יפעלו לקבל שידורים שלCONNECTIVITY_ACTION
אם הם יירשמוBroadcastReceiver
עםContext.registerReceiver()
וההקשר הזה עדיין תקף. - אפליקציות לא יכולות לשלוח או לקבל שידורים של
ACTION_NEW_PICTURE
אוACTION_NEW_VIDEO
. האופטימיזציה הזו משפיעה על כל האפליקציות, לא רק על אלה שמטרגטות ל-Android 7.0 (רמת API 24).
אם האפליקציה משתמשת באחד מהאובייקטים האלה של Intent, צריך להסיר את יחסי התלות שבהם
בהקדם האפשרי כדי לטרגט כראוי מכשירים עם Android 7.0
ומעלה. מערכת Android מספקת כמה פתרונות כדי לצמצם
לצורך השידורים המרומזים האלה. לדוגמה, JobScheduler
וגם
WorkManager החדש מספק מנגנונים יעילים לתזמון רשתות
כאשר מתקיימים התנאים המוגדרים, כמו חיבור לרשת
עומדים בדרישות. עכשיו אפשר גם להשתמש באפליקציית JobScheduler
כדי להגיב לשינויים שיבוצעו בספקי התוכן. JobInfo
אובייקטים כוללים את הפרמטרים ש-JobScheduler
שבו נעשה שימוש כדי לתזמן את העבודה שלך. כשתנאי המשימה מתקיימים, המערכת
מבצע את המשימה הזו ב-JobService
של האפליקציה.
בדף הזה נלמד איך להשתמש בשיטות חלופיות, כמו
JobScheduler
, כדי להתאים את האפליקציה שלך לשינויים האלה
ההגבלות.
הגבלות ביוזמת המשתמש
בדף שימוש בסוללה בתוך המערכת הגדרות, המשתמש יכול צריך לבחור אחת מהאפשרויות הבאות:
- ללא הגבלה: הרשאה לביצוע כל העבודה ברקע, שעלולה לגרום לצריכת סוללה גבוהה יותר.
- אופטימיזציה (ברירת מחדל): אופטימיזציה ליכולת של האפליקציה לבצע עבודה ברקע, על סמך האינטראקציה של המשתמש עם האפליקציה.
- מוגבלת: ההגדרה הזו מונעת לגמרי מאפליקציה לפעול ברקע. קמפיינים לקידום אפליקציות ייתכן שלא יפעל כצפוי.
אם אפליקציה מציגה חלק מההתנהגויות הלא תקינות שמתוארות ב-Android תפקוד האפליקציה, המערכת עשויה לבקש מהמשתמש להגביל את הגישה של האפליקציה למשאבי המערכת.
אם המערכת מזהה שאפליקציה צורכת יותר מדי משאבים, היא שולחת התראה משתמש ומאפשר לו להגביל את הפעולות של האפליקציה. התנהגויות שיכולות להפעיל את ההתראה:
- יותר מדי חסימות מצב שינה: נעילת מצב שינה חלקית אחת מוחזקת למשך שעה כשהמסך כבוי
- שימוש מוגזם בשירותי רקע: אם האפליקציה מטרגטת רמות API שנמוכות מ-26 ויש לה שימוש מוגזם בשירותי רקע
ההגבלות המדויקות שהוטלו נקבעות על ידי יצרן המכשיר. עבור לדוגמה, בגרסאות build של AOSP עם Android 9 (רמת API 28) ואילך, אפליקציות פועלות ברקע שנמצאות במצב "מוגבל" כוללים את הפרטים הבאים מגבלות:
- אי אפשר להפעיל שירותים שפועלים בחזית
- שירותים קיימים שפועלים בחזית יוסרו מהחזית
- ההתראות לא מופעלות
- המשימות לא מבוצעות
כמו כן, אם אפליקציה מטרגטת את Android 13 (רמת API 33) ואילך, והיא נמצאת
"מוגבל" המצב הזה, המערכת לא מספקת את השידור של BOOT_COMPLETED
או
את השידור LOCKED_BOOT_COMPLETED
עד שהאפליקציה תופעל במכשירים אחרים
סיבות נוספות.
ההגבלות הספציפיות האלה מפורטות הגבלות על ניהול צריכת החשמל.
הגבלות על קבלת שידורי פעילות ברשת
אפליקציות שמטרגטות ל-Android 7.0 (רמת API 24) לא מקבלות שידורים של CONNECTIVITY_ACTION
אם הן
להירשם כדי לקבל אותן במניפסט ובתהליכים שתלויים
השידור לא יתחיל. הדבר עלול ליצור בעיה באפליקציות שרוצות
כדי להאזין לשינויים ברשת או לבצע פעילויות ברשת בכמות גדולה כאשר
שהמכשיר מתחבר לרשת שאינה בשימוש לפי שימוש בנתונים. יש כמה פתרונות אפשריים
כבר קיימות ב-framework של Android, אבל בחירת
אחת תלויה במה שרוצים שהאפליקציה שלכם להשיג.
הערה: BroadcastReceiver
רשום אצל
Context.registerReceiver()
ימשיך לקבל את השידורים האלה בזמן שהאפליקציה פועלת.
תזמון משימות ברשת בחיבורים ללא חיוב לפי שימוש בנתונים
כשמשתמשים בכיתה JobInfo.Builder
כדי לבנות את האובייקט JobInfo
, צריך להחיל את השיטה setRequiredNetworkType()
ולהעביר את JobInfo.NETWORK_TYPE_UNMETERED
כפרמטר של משימה. דוגמת הקוד הבאה
מתזמנת הפעלה של שירות כשהמכשיר מתחבר לרשת סלולרית
ברשת ונטען:
Kotlin
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MyJobService::class.java) ) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build() jobScheduler.schedule(job) }
Java
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo job = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MyJobService.class)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build(); js.schedule(job); }
כשהתנאים של המשימה מתקיימים, האפליקציה תקבל קריאה חוזרת (callback) כדי שהיא תוכל לפעול
השיטה onStartJob()
ב
ציינת JobService.class
. כדי לראות דוגמאות נוספות של הטמעת JobScheduler
, אפשר להיכנס לאפליקציה לדוגמה של JobScheduler.
חלופה חדשה ל-JobScheduler היא WorkManager, ממשק API שמאפשר לתזמן משימות ברקע מובטחת השלמה, בין אם תהליך האפליקציה זמין ובין אם לא. מנהל עבודה בוחר את הדרך המתאימה להריץ את העבודה (ישירות בשרשור בתהליך האפליקציה, וגם שימוש ב-JobScheduler, FirebaseJobDispatcher או AlertManager) על סמך גורמים כמו רמת ה-API של המכשיר. בנוסף, WorkManager לא דורש את שירותי Play ומספק מספר תכונות מתקדמות, כמו שרשור של משימות ביחד או בדיקת סטטוס של משימה. למידה למידע נוסף, ראו WorkManager.
מעקב אחר קישוריות הרשת בזמן שהאפליקציה פועלת
אפליקציות פועלות עדיין יכולות להאזין לCONNECTIVITY_CHANGE
עם
נרשם ב-BroadcastReceiver
. אבל ה-API של ConnectivityManager
מספק שיטה מתקדמת יותר לשליחת בקשה
קריאה חוזרת (callback) רק כשתנאי הרשת שצוינו מתקיימים.
NetworkRequest
אובייקטים מגדירים את הפרמטרים
קריאה חוזרת ברשת במונחים של NetworkCapabilities
. שלך
ליצור NetworkRequest
אובייקטים עם המחלקה NetworkRequest.Builder
. registerNetworkCallback()
לאחר מכן הוא מעביר את האובייקט NetworkRequest
למערכת. מתי
שתנאי הרשת מתקיימים, האפליקציה מקבלת קריאה חוזרת כדי לבצע
השיטה onAvailable()
הוגדרה במחלקה ConnectivityManager.NetworkCallback
.
האפליקציה תמשיך לקבל קריאות חוזרות (callback) עד שהיא תצא מהאפליקציה או שהיא תבצע שיחה
unregisterNetworkCallback()
הגבלות על קבלת שידורים של תמונות וסרטונים
ב-Android 7.0 (רמת API 24), אין לאפליקציות אפשרות לשלוח או לקבל שידורים של ACTION_NEW_PICTURE
או ACTION_NEW_VIDEO
. ההגבלה הזו עוזרת
להפחית את ההשפעה על הביצועים וחוויית המשתמש כאשר מספר אפליקציות
להוציא ממצב שינה כדי לעבד תמונה או סרטון חדשים. Android 7.0 (רמת API 24)
להרחיב את JobInfo
ואת JobParameters
כדי לספק פתרון חלופי.
הפעלת משימות בשינויי URI של תוכן
כדי להפעיל משימות בשינויי URI של תוכן, Android 7.0 (רמת API 24) מורחב
ה-API JobInfo
באמצעות השיטות הבאות:
-
JobInfo.TriggerContentUri()
- כולל את הפרמטרים הנדרשים להפעלת משימה בשינויי URI של תוכן.
-
JobInfo.Builder.addTriggerContentUri()
-
מעביר אובייקט
TriggerContentUri
אלJobInfo
.ContentObserver
עוקב אחר ה-URI של התוכן המקודד. אם יש מספר אובייקטים שלTriggerContentUri
שמשויכים למשימה, המערכת מספקת גם אם היא מדווחת על שינוי באחד ממזהי ה-URI של התוכן. -
הוספת הדגל
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
אל להפעיל את המשימה אם משתנים צאצאים של ה-URI הנתון. הדגל הזה תואם לפרמטרnotifyForDescendants
שהועבר אלregisterContentObserver()
.
הערה: לא ניתן להשתמש במאפיין TriggerContentUri()
ב:
בשילוב עם setPeriodic()
או עם setPersisted()
. כדי לעקוב ברציפות אחר שינויים בתוכן, לתזמן
JobInfo
לפני סיום הטיפול בקריאה חוזרת (callback) של האפליקציה ב-JobService
.
הקוד לדוגמה הבא מתזמנ משימה להפעלה כשהמערכת מדווחת
שינוי ב-URI של התוכן, MEDIA_URI
:
Kotlin
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MediaContentJob::class.java) ) .addTriggerContentUri( JobInfo.TriggerContentUri( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS ) ) .build() jobScheduler.schedule(job) }
Java
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MediaContentJob.class)); builder.addTriggerContentUri( new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); js.schedule(builder.build()); }
כשהמערכת מדווחת על שינוי ב-URI של התוכן שצוין, האפליקציה שלכם
מקבל קריאה חוזרת ואובייקט JobParameters
הועבר אל onStartJob()
ב-MediaContentJob.class
.
איך בודקים אילו רשויות תוכן הפעילו משימה
Android 7.0 (רמת API 24) נמשכת גם JobParameters
עד
מאפשרת לאפליקציה לקבל מידע שימושי על רשויות התוכן
ו-URI הפעילו את המשימה:
-
Uri[] getTriggeredContentUris()
-
מחזירה מערך של מזהי URI שהפעילו את המשימה. הערך יהיה
null
אם אין מזהי URI שהפעילו את המשימה (לדוגמה, המשימה בעקבות תאריך יעד או מסיבה אחרת), או מספר השינויים מספר מזהי ה-URI גדול מ-50. -
String[] getTriggeredContentAuthorities()
-
מחזירה מערך מחרוזות של רשויות תוכן שהפעילו את המשימה.
אם המערך המוחזר אינו
null
, יש להשתמש ב-getTriggeredContentUris()
כדי לאחזר את הפרטים של מזהי ה-URI שהשתנו.
הקוד לדוגמה הבא מבטל את ה-method JobService.onStartJob()
ו
מתעד את רשויות התוכן ומזהי ה-URI שהפעילו את המשימה:
Kotlin
override fun onStartJob(params: JobParameters): Boolean { StringBuilder().apply { append("Media content has changed:\n") params.triggeredContentAuthorities?.also { authorities -> append("Authorities: ${authorities.joinToString(", ")}\n") append(params.triggeredContentUris?.joinToString("\n")) } ?: append("(No content)") Log.i(TAG, toString()) } return true }
Java
@Override public boolean onStartJob(JobParameters params) { StringBuilder sb = new StringBuilder(); sb.append("Media content has changed:\n"); if (params.getTriggeredContentAuthorities() != null) { sb.append("Authorities: "); boolean first = true; for (String auth : params.getTriggeredContentAuthorities()) { if (first) { first = false; } else { sb.append(", "); } sb.append(auth); } if (params.getTriggeredContentUris() != null) { for (Uri uri : params.getTriggeredContentUris()) { sb.append("\n"); sb.append(uri); } } } else { sb.append("(No content)"); } Log.i(TAG, sb.toString()); return true; }
ביצוע אופטימיזציה נוספת לאפליקציה
אופטימיזציה של האפליקציות כך שיפעלו במכשירים עם נפח זיכרון נמוך או עם נפח זיכרון נמוך יכולים לשפר את הביצועים ואת חוויית המשתמש. מתבצעת הסרה או תלות בשירותי רקע ובגישה משתמעת משתמעת במניפסט מקלטי שידור יכולים לעזור לאפליקציה שלך לפעול טוב יותר במכשירים כאלה. למרות מערכת Android 7.0 (רמת API 24) נוקטת פעולות כדי לצמצם חלק מהבעיות האלה, מומלץ לבצע אופטימיזציה של האפליקציה כך שתפעל בלי להשתמש תהליכי רקע לחלוטין.
הממשק הבא של הגשר לניפוי באגים ב-Android (ADB) פקודות יכולות לעזור לכם לבדוק את התנהגות האפליקציה כשתהליכים ברקע מושבתים:
- לדמות תנאים שבהם שידורים מרומזים ושירותים ברקע אינן זמינות, צריך להזין את הפקודה הבאה:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
- כדי להפעיל מחדש שידורים מרומזים ושירותים ברקע, מזינים את הפקודה הבאה:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
- אפשר לדמות את המשתמש שמציב את האפליקציה בקטע 'מוגבל' מדינה עבור שימוש בסוללה ברקע. ההגדרה הזו מונעת מהאפליקציה לפעול ברקע. כדי לעשות זאת, מריצים את הפקודה הבאה בחלון טרמינל:
-
$ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny