לעתים קרובות אפליקציות צריכות לבצע יותר מפעולה אחת בו-זמנית. ממשקי ה-API של Android מספקים הרבה דרכים שונות לעשות זאת. חשוב מאוד לבחור את האפשרות הנכונה. יכול להיות שאפשרות מסוימת מתאימה למצב אחד, אבל לא מתאימה למצב אחר. בחירה לא נכונה של ממשקי ה-API עלולה לפגוע בביצועים או ביעילות השימוש במשאבים של האפליקציה, וכתוצאה מכך לרוקן את הסוללה ולפגוע בביצועים של המכשיר של המשתמש באופן כללי. במקרים מסוימים, בחירה בגישה הלא נכונה עלולה למנוע את הוספת האפליקציה שלכם לחנות Play.
במסמך הזה מוסבר על האפשרויות השונות שזמינות לכם, ונסביר איך לבחור את האפשרות המתאימה למצב שלכם.
טרמינולוגיה
יש מונחים חשובים שקשורים למשימות ברקע שיכול להיות שנעשה בהם שימוש במספר דרכים סותרות. לכן חשוב להגדיר את המונחים שלנו.
אם אפליקציה פועלת ברקע, המערכת מחילה עליה כמה הגבלות. (לדוגמה, ברוב המקרים אפליקציה ברקע לא יכולה להפעיל שירותים בחזית).
במסמך הזה, המונח 'משימה' יתייחס לביצוע פעולה על ידי אפליקציה מחוץ לתהליך העבודה הראשי שלה. כדי להבטיח שהכול ברור, סידרנו את סוגי המשימות בשלוש קטגוריות עיקריות: עבודה אסינכררונית, ממשקי ה-API לתזמון משימות ושירותים בחזית.
בחירת האפשרות המתאימה
ברוב התרחישים, אפשר להבין אילו ממשקי API מתאימים למשימה על ידי זיהוי הקטגוריה (עבודה אסינכררונית, ממשקי API לתזמון משימות או שירותי חזית) שבה היא נכללת.
אם אתם עדיין לא בטוחים, תוכלו להיעזר בתרשים התהליך שאנחנו מספקים כדי לקבל החלטה מושכלת יותר. בהמשך המאמר נפרט על כל אחת מהאפשרויות האלה.
יש שני תרחישים עיקריים שצריך להביא בחשבון לגבי משימות ברקע:
לשני התרחישים האלה יש עצי החלטות משלהם.
עבודה אסינכרונית
במקרים רבים, אפליקציה צריכה רק לבצע פעולות בו-זמנית בזמן שהיא פועלת בחזית. לדוגמה, יכול להיות שאפליקציה תצטרך לבצע חישוב שאורך זמן רב. אם החישוב יתבצע בשרשור של ממשק המשתמש, המשתמש לא יוכל לבצע פעולות באפליקציה עד שהחישוב יסתיים. כתוצאה מכך, עשויה להופיע שגיאת ANR. במקרה כזה, האפליקציה צריכה להשתמש באפשרות עבודה אסינכרוני.
אפשרויות נפוצות לעבודה אסינכרונית כוללות קורוטינים של Kotlin ושרשראות של Java. מידע נוסף זמין במאמר העזרה בנושא עבודה אסינכרונית. חשוב לציין שבניגוד לממשקי ה-API של משימות ברקע, לא מובטח שהעבודה האסינכרונית תסתיים אם האפליקציה תפסיק להיות בשלב תקין של מחזור החיים (לדוגמה, אם האפליקציה תצא מחזית המסך).
ממשקי API לתזמון משימות
ממשקי ה-API לתזמון משימות הם אופציה גמישה יותר כשצריך לבצע משימות שצריכות להמשיך גם אם המשתמש יוצא מהאפליקציה. ברוב המקרים, האפשרות הטובה ביותר להרצת משימות ברקע היא להשתמש ב-WorkManager, אבל במקרים מסוימים ייתכן שיהיה צורך להשתמש ב-API של הפלטפורמה JobScheduler
.
WorkManager היא ספרייה חזקה שמאפשרת להגדיר משימות פשוטות או מורכבות לפי הצורך. אפשר להשתמש ב-WorkManager כדי לתזמן משימות כך שיפעלו בזמנים ספציפיים, או לציין את התנאים שבהם המשימה צריכה לפעול. אפשר גם להגדיר שרשרת של משימות, כך שכל משימה תרוץ בתורו ותעביר את התוצאות שלה למשימה הבאה. כדי להבין את כל האפשרויות הזמינות, כדאי לקרוא את רשימת התכונות של WorkManager.
אלה כמה מהתרחישים הנפוצים ביותר למשימות ברקע:
- אחזור נתונים מהשרת מדי פעם
- אחזור נתוני חיישנים (לדוגמה, נתונים ממונה הצעדים)
- אחזור נתוני מיקום תקופתיים (נדרשת הרשאה
ACCESS_BACKGROUND_LOCATION
ב-Android 10 ואילך) - העלאת תוכן על סמך טריגר תוכן, כמו תמונות שנוצרו באמצעות המצלמה
שירותים שפועלים בחזית
שירותים שפועלים בחזית הם דרך יעילה להריץ משימות באופן מיידי, בלי שאפשר יהיה להפריע להן. עם זאת, שירותים בחזית עלולים להעמיס על המכשיר, ולפעמים יש להם השלכות על הפרטיות והאבטחה. לכן, המערכת מטילה הרבה הגבלות על האופן שבו האפליקציות יכולות להשתמש בשירותים שפועלים בחזית, ועל הזמנים שבהם הן יכולות לעשות זאת. לדוגמה, שירות בחזית צריך להיות בולט למשתמש, וברוב המקרים אפליקציות לא יכולות להפעיל שירותים בחזית כשהן נמצאות ברקע. מידע נוסף זמין במסמכי העזרה של שירותי החזית.
יש שתי שיטות ליצירת שירות שפועל בחזית. אפשר להצהיר על Service
משלכם ולציין שהשירות הוא שירות שפועל בחזית על ידי קריאה ל-Service.startForeground()
. לחלופין, אפשר להשתמש ב-WorkManager כדי ליצור שירות שפועל בחזית, כפי שמתואר בקטע תמיכה בעובדים לטווח ארוך.
עם זאת, חשוב לדעת ששירות שפועל בחזית שנוצר על ידי WorkManager חייב לציית לכל אותן הגבלות כמו כל שירות אחר שפועל בחזית.
WorkManager מספק רק כמה ממשקי API נוחים כדי שיהיה קל יותר ליצור שירות בחזית.
ממשקי API חלופיים
המערכת מציעה ממשקי API חלופיים שנועדו לספק ביצועים טובים יותר בתרחישי שימוש ספציפיים יותר. אם קיים ממשק API חלופי לתרחיש לדוגמה שלכם, מומלץ להשתמש בו במקום בשירות שפועל בחזית, כי הוא אמור לשפר את הביצועים של האפליקציה. במסמכי העזרה בנושא סוגי שירותים שפועלים בחזית מצוין מתי יש ממשק API חלופי מתאים שאפשר להשתמש בו במקום סוג מסוים של שירות שפועל בחזית.
אלה כמה מהתרחישים הנפוצים ביותר לשימוש בממשקי API חלופיים:
- שימוש בהעברות נתונים ביוזמת המשתמש כדי לבצע הורדות או העלאות גדולות, במקום ליצור שירות חזית לסנכרון נתונים
- שימוש במנהל המכשיר הנלווה להתאמה ב-Bluetooth ולהעברת נתונים, במקום להשתמש בשירות בחזית של מכשיר מחובר
- שימוש במצב 'תמונה בתוך תמונה' להפעלת סרטון, במקום ליצור שירות בחזית למדיה להפעלת מדיה
משימות שהמשתמש יצר
אם אפליקציה צריכה לבצע משימות ברקע, והפעולה מופעלת על ידי המשתמש בזמן שהאפליקציה גלויה, תוכלו לענות על השאלות הבאות כדי למצוא את הגישה המתאימה.
האם המשימה צריכה להמשיך לפעול בזמן שהאפליקציה פועלת ברקע?
אם אין צורך שהמשימה תמשיך לפעול בזמן שהאפליקציה נמצאת ברקע, כדאי להשתמש בעבודה אסינכררונית. יש כמה אפשרויות לביצוע עבודה אסינכררונית. חשוב להבין שכל האפשרויות האלה מפסיקות לפעול אם האפליקציה עוברת לרקע. (הפעולות האלה מופסקות גם אם האפליקציה מושבתת). לדוגמה, אפליקציה של רשת חברתית עשויה לרענן את פיד התוכן שלה, אבל היא לא תצטרך להשלים את הפעולה אם המשתמש עזב את המסך.
האם חוויית המשתמש תהיה גרועה אם המשימה תידחה או תופסק?
חשוב לבדוק אם דחיית המשימה או ביטולה תפגע בחוויית המשתמש. לדוגמה, אם אפליקציה צריכה לעדכן את הנכסים שלה, יכול להיות שהמשתמש לא יבחין אם הפעולה מתבצעת מיד או באמצע הלילה בזמן שהמכשיר נטען. במקרים כאלה, כדאי להשתמש באפשרויות של עבודה ברקע.
האם זו משימה קצרה וקריטית?
אם אי אפשר לדחות את המשימה והיא תסתיים במהירות, אפשר להשתמש בשירות שפועל בחזית מסוג shortService
. קל יותר ליצור את השירותים האלה מאשר שירותים אחרים שפועלים בחזית, והם לא דורשים הרבה הרשאות. עם זאת, שירותים קצרים חייבים להסתיים תוך שלוש דקות.
האם יש ממשק API חלופי למטרה הזו?
אם המשימה לא מוסתר מהמשתמש, יכול להיות שהפתרון הנכון הוא להשתמש בשירות שפועל בחזית. השירותים האלה פועלים ברציפות אחרי שהם מופעלים, ולכן הם בחירה טובה כשהפרעה למשימה תגרום לחוויית משתמש גרועה. לדוגמה, אפליקציה למעקב אחר אימונים עשויה להשתמש בחיישני מיקום כדי לאפשר למשתמשים לתעד את מסלול הריצה שלהם במפה. לא מומלץ לעשות זאת עם אפשרות לעבודה ברקע, כי אם המשימה תושהה, המעקב ייפסק מיד. במצב כזה, שירות שפועל בחזית הוא הפתרון הטוב ביותר.
עם זאת, מכיוון ששירותים שפועלים בחזית יכולים להשתמש במספר רב של משאבי המכשיר, המערכת מטילה הגבלות רבות על מועד השימוש בהם ועל האופן שבו אפשר להשתמש בהם. במקרים רבים, במקום להשתמש בשירות שפועל בחזית, אפשר להשתמש בAPI חלופי שיטפל בעבודה בשבילכם בקלות רבה יותר. לדוגמה, אם האפליקציה צריכה לבצע פעולה כשהמשתמש מגיע למיקום מסוים, האפשרות הטובה ביותר היא להשתמש ב-Geofence API במקום לעקוב אחרי המיקום של המשתמש באמצעות שירות שפועל בחזית.
משימות בתגובה לאירוע
לפעמים אפליקציה צריכה לבצע משימות ברקע בתגובה לטריגר, למשל:
- שידור הודעות
- הודעות של העברת הודעות בענן ב-Firebase (FCM)
- התראות שהוגדרו על ידי האפליקציה
יכול להיות שמדובר בטריגר חיצוני (כמו הודעת FCM) או בתגובה לאזעקה שהאפליקציה עצמה הגדרה. לדוגמה, יכול להיות שתוכלו לקבל הודעה מ-FCM על עדכון של נכסים מסוימים במשחק.
אם אתם יכולים להיות בטוחים שהמשימה תסתיים תוך כמה שניות, השתמשו בעבודה אסינכררונית כדי לבצע אותה. המערכת תאפשר לאפליקציה כמה שניות לבצע משימות כאלה, גם אם האפליקציה הייתה ברקע.
אם המשימה נמשכת יותר מכמה שניות, מומלץ להפעיל שירות בחזית כדי לטפל במשימה. למעשה, גם אם האפליקציה נמצאת כרגע ברקע, יכול להיות שתהיה לה הרשאה להפעיל שירות שפועל בחזית, אם המשימה הופעלה על ידי המשתמש והיא נכללת באחד מהפטורים המאושרים מההגבלות על הפעלה ברקע. לדוגמה, אם אפליקציה מקבלת הודעת FCM בעדיפות גבוהה, היא רשאית להפעיל שירות בחזית גם אם היא פועלת ברקע.
אם המשימה נמשכת יותר מכמה שניות, כדאי להשתמש בממשקי ה-API לתזמון משימות.