תזמון התראות

התראות (על סמך הכיתה AlarmManager) מאפשרות לבצע פעולות מבוססות-זמן מחוץ לטווח החיים של האפליקציה. לדוגמה, אפשר להשתמש בהתראה כדי להפעיל פעולה ממושכת, כמו הפעלת שירות פעם ביום כדי להוריד תחזית מזג אוויר.

למעוררים יש את המאפיינים הבאים:

  • הם מאפשרים להפעיל כוונות (intents) במועדים מוגדרים ו/או במרווחי זמן מוגדרים.

  • אפשר להשתמש בהם בשילוב עם מקלטי שידור כדי לתזמן משימות או בקשות WorkRequest כדי לבצע פעולות אחרות.

  • הן פועלות מחוץ לאפליקציה, כך שאפשר להשתמש בהן כדי להפעיל אירועים או פעולות גם כשהאפליקציה לא פועלת, ואפילו כשהמכשיר עצמו במצב שינה.

  • הם עוזרים לכם לצמצם את דרישות המשאבים של האפליקציה. אפשר לתזמן פעולות בלי להסתמך על טיימרים או על שירותים שפועלים באופן רציף.

הגדרת התראה לא מדויקת

כשאפליקציה מגדירה התראה לא מדויקת, המערכת מפעילה את ההתראה בשלב כלשהו בעתיד. התראות לא מדויקות מספקות התחייבויות מסוימות לגבי תזמון ההתראות, תוך שמירה על הגבלות לחיסכון בסוללה, כמו Doze.

מפתחים יכולים להשתמש בהתחייבויות הבאות של ה-API כדי להתאים אישית את התזמון של שליחת ההתראות הלא מדויקות.

שליחת התראה אחרי שעה מסוימת

אם האפליקציה שלכם קוראת ל-set(),‏ setInexactRepeating() או setAndAllowWhileIdle(), ההתראה לא תופעל לפני מועד ההפעלה שצוין.

ב-Android 12 (רמת API 31) ואילך, המערכת מפעילה את ההתראה תוך שעה אחת ממועד ההפעלה שצוין, אלא אם יש הגבלות חיסכון בסוללה כמו מצב חיסכון בסוללה או Doze.

שליחת התראה במהלך חלון זמן

אם האפליקציה שלכם קוראת ל-setWindow(), ההתראה אף פעם לא תופעל לפני זמן ההפעלה שצוין. אלא אם יש הגבלות לחיסכון בסוללה, ההתראה תוצג בחלון הזמן שצוין, החל מהשעה שצוינה להפעלה.

אם האפליקציה שלכם מטרגטת את Android מגרסה 12 ואילך, המערכת יכולה לעכב את ההפעלה של אזעקה לא מדויקת עם חלון זמן של 10 דקות לפחות. לכן, ערכים של הפרמטר windowLengthMillis מתחת ל-600000 נחתכים ל-600000.

שליחת התראה חוזרת במרווחי זמן יחסית קבועים

אם האפליקציה קוראת ל-setInexactRepeating(), המערכת מפעילה כמה התראות:

  1. ההתראה הראשונה תופעל בחלון הזמן שצוין, החל משעת ההפעלה שצוינה.
  2. בדרך כלל, ההתראות הבאות מופעלות אחרי שחלון הזמן שצוין מסתיים. הזמן שחולף בין שתי הפעלות רצופות של ההתראה עשוי להשתנות.

הגדרת התראה מדויקת

המערכת מפעילה התראה מדויקת ברגע מדויק בעתיד.

ברוב האפליקציות אפשר לתזמן משימות ואירועים באמצעות שעונים מעוררים לא מדויקים כדי לבצע כמה תרחישים נפוצים לדוגמה. אם הפונקציונליות העיקרית של האפליקציה תלויה בהתראה מתוזמנת במדויק – למשל, באפליקציית שעון מעורר או באפליקציית יומן – מותר להשתמש במקום זאת בהתראה מדויקת.

תרחישים לדוגמה שבהם יכול להיות שלא יהיה צורך בהתראות מדויקות

ברשימה הבאה מפורטים תהליכי עבודה נפוצים שיכול להיות שלא ידרשו התראה מדויקת:

תזמון פעולות במהלך מחזור החיים של האפליקציה
הקלאס Handler כולל כמה שיטות טובות לטיפול בפעולות תזמון, כמו ביצוע עבודה כל n שניות, בזמן שהאפליקציה פעילה: postAtTime() ו-postDelayed(). חשוב לדעת שממשקי ה-API האלה מסתמכים על זמן פעולה תקינה של המערכת ולא על זמן אמת.
עבודות רקע מתוזמנות, כמו עדכון האפליקציה והעלאת יומנים
WorkManager מאפשר לתזמן משימות תקופתיות שחשוב שהן יבוצעו בזמן. אפשר לציין מרווח זמן לחזרה ו-flexInterval (15 דקות לפחות) כדי להגדיר זמן ריצה מפורט של העבודה.
פעולה שצוינה על ידי המשתמש שתתבצע לאחר פרק זמן מסוים (גם אם המערכת במצב חוסר פעילות)
שימוש בהתראה לא מדויקת. באופן ספציפי, צריך לקרוא לפונקציה setAndAllowWhileIdle().
פעולה שהמשתמש מציין שצריכה להתרחש אחרי זמן ספציפי
שימוש בהתראה לא מדויקת. באופן ספציפי, צריך לקרוא לפונקציה set().
פעולה שהמשתמש ציין שיכולה להתרחש בחלון זמן מסוים
שימוש בהתראה לא מדויקת. באופן ספציפי, צריך לקרוא לפונקציה setWindow(). שימו לב: אם האפליקציה שלכם מטרגטת את Android מגרסה 12 ואילך, אורך החלון המינימלי המותרת הוא 10 דקות.

דרכים להגדרת התראה מדויקת

האפליקציה יכולה להגדיר התראות מדויקות באחת מהשיטות הבאות. השיטות האלה ממוינות כך שהשיטות שנמצאות קרוב לתחתית הרשימה משמשות למשימות קריטיות יותר מבחינת זמן, אבל דורשות יותר משאבי מערכת.

setExact()

להפעיל התראה בשעה מדויקת כמעט בעתיד, כל עוד לא פועלות אמצעי חיסכון אחרים בסוללה.

מומלץ להשתמש בשיטה הזו כדי להגדיר התראות מדויקות, אלא אם העבודה של האפליקציה קריטית למשתמש מבחינת זמן.

setExactAndAllowWhileIdle()

להפעיל אזעקה בשעה מדויקת כמעט בעתיד, גם אם פועלים אמצעי חיסכון בסוללה.

setAlarmClock()

להפעיל שעון מעורר בשעה מדויקת בעתיד. ההתראות האלה גלויות מאוד למשתמשים, ולכן המערכת אף פעם לא משנה את מועד השליחה שלהן. המערכת מזהה את ההתראות האלה כקריטיות ביותר, ומוצאת את עצמה במצבי צריכת אנרגיה נמוכה אם צריך כדי לשלוח את ההתראות.

צריכת משאבי המערכת

כשהמערכת מפעילה התראות מדויקות שהגדרתם באפליקציה, המכשיר צורך הרבה משאבים, כמו חיי הסוללה, במיוחד אם הוא במצב חיסכון באנרגיה. בנוסף, המערכת לא יכולה לאסוף בקלות את הבקשות האלה כדי לנצל את המשאבים בצורה יעילה יותר.

מומלץ מאוד ליצור התראה לא מדויקת כשהדבר אפשרי. כדי לבצע עבודה ארוכה יותר, תוכלו לתזמן אותה באמצעות WorkManager או JobScheduler בBroadcastReceiver של השעון המעורר. כדי לבצע משימות בזמן שהמכשיר במצב שינה, יוצרים התראה לא מדויקת באמצעות setAndAllowWhileIdle() ומתחילים את המשימה מההתראה.

הצהרה על ההרשאה המתאימה להתראות מדויקות

אם האפליקציה שלכם מטרגטת ל-Android 12 ואילך, עליכם לקבל את הרשאת הגישה המיוחדת 'התראות ותזכורות'. לשם כך, מגדירים את ההרשאה SCHEDULE_EXACT_ALARM בקובץ המניפסט של האפליקציה, כפי שמתואר בקטע הקוד הבא:

<manifest ...>
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

אם האפליקציה שלכם מטרגטת ל-Android 13 (רמת API 33) ואילך, אתם יכולים להצהיר על ההרשאה SCHEDULE_EXACT_ALARM או על ההרשאה USE_EXACT_ALARM.

<manifest ...>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

ההרשאות SCHEDULE_EXACT_ALARM ו-USE_EXACT_ALARM מסמנות את אותן יכולות, אבל הן מוענקות באופן שונה ותומכות בתרחישי שימוש שונים. מומלץ להשתמש באפליקציה בהתראות מדויקות ולהצהיר על ההרשאה SCHEDULE_EXACT_ALARM או USE_EXACT_ALARM רק אם פונקציה גלויה למשתמשים באפליקציה מחייבת פעולות עם תזמון מדויק.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • הוקצו על ידי המשתמש
  • קבוצה רחבה יותר של תרחישים לדוגמה
  • האפליקציות צריכות לוודא שההרשאה לא בוטלה

ההרשאה SCHEDULE_EXACT_ALARM לא ניתנת מראש להתקנות חדשות של אפליקציות שמטרגטות את Android 13 (רמת API ‏33) ואילך. אם משתמש מעביר נתוני אפליקציה למכשיר עם Android 14 באמצעות פעולת גיבוי ושחזור, ההרשאה SCHEDULE_EXACT_ALARM תידחה במכשיר החדש. עם זאת, אם לאפליקציה קיימת כבר יש את ההרשאה הזו, היא תוענק מראש כשהמכשיר יתעדכן ל-Android 14.

הערה: אם ההתראה המדויקת מוגדרת באמצעות אובייקט OnAlarmListener, למשל באמצעות ה-API setExact, לא נדרשת ההרשאה SCHEDULE_EXACT_ALARM.

שימוש בהרשאה SCHEDULE_EXACT_ALARM

בניגוד להרשאה USE_EXACT_ALARM, ההרשאה SCHEDULE_EXACT_ALARM צריכה להינתן על ידי המשתמש. גם המשתמש וגם המערכת יכולים לבטל את ההרשאה SCHEDULE_EXACT_ALARM.

כדי לבדוק אם ההרשאה הוענקה לאפליקציה, צריך להפעיל את הפונקציה canScheduleExactAlarms() לפני שמנסים להגדיר התראה מדויקת. אם ההרשאה SCHEDULE_EXACT_ALARM תבוטל באפליקציה, היא תפסיק לפעול וכל ההתראות המדויקות העתידיות יבוטלו. המשמעות היא גם שהערך שמוחזר על ידי canScheduleExactAlarms() נשאר תקף לכל משך מחזור החיים של האפליקציה.

כשהאפליקציה מקבלת את ההרשאה SCHEDULE_EXACT_ALARMS, המערכת שולחת לה את השידור ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED. באפליקציה צריך להטמיע מקלט שידור שמבצע את הפעולות הבאות:

  1. מוודאים שלאפליקציה עדיין יש את הרשאת הגישה המיוחדת. כדי לעשות זאת, מפעילים את הפקודה canScheduleExactAlarms(). הבדיקה הזו מגינה על האפליקציה במקרה שבו המשתמש מעניק לאפליקציה את ההרשאה, ואז מבטל אותה כמעט מיד לאחר מכן.
  2. תזמון מחדש של כל ההתראות המדויקות שנדרשות לאפליקציה, על סמך המצב הנוכחי שלה. הלוגיקה הזו צריכה להיות דומה למה שהאפליקציה עושה כשהיא מקבלת את השידור ACTION_BOOT_COMPLETED.

בקשה מהמשתמשים להעניק את ההרשאה SCHEDULE_EXACT_ALARM

האפשרות נקראת &#39;אישור להגדיר שעונים מעוררים ותזכורות&#39;.
איור 1. דף ההרשאות המיוחדות של האפליקציה 'התראות ותזכורות' בהגדרות המערכת, שבו המשתמשים יכולים לאפשר לאפליקציה להגדיר התראות מדויקות.

אם יש צורך, אפשר לשלוח את המשתמשים למסך התראות ותזכורות בהגדרות המערכת, כפי שמוצג באיור 1. כדי לעשות זאת, מבצעים את השלבים הבאים:

  1. בממשק המשתמש של האפליקציה, צריך להסביר למשתמש למה האפליקציה צריכה לתזמן התראות מדויקות.
  2. קוראים ל-Intent שכולל את פעולת ה-Intent‏ ACTION_REQUEST_SCHEDULE_EXACT_ALARM.

הגדרת התראה חוזרת

התראות חוזרות מאפשרות למערכת לשלוח התראות לאפליקציה שלכם לפי לוח זמנים קבוע.

התראה שתוכננה בצורה לא טובה עלולה לרוקן את הסוללה ולהעמיס באופן משמעותי על השרתים. לכן, ב-Android 4.4 (רמת API 19) ואילך, כל ההתראות החוזרות הן התראות לא מדויקות.

התכונות של ההתראה החוזרת הן:

  • סוג ההתראה. מידע נוסף זמין במאמר בחירת סוג התראה.

  • מועד הפעלה. אם השעה להפעלה שציינתם כבר עברה, ההתראה תופעל באופן מיידי.

  • המרווח בין ההתראות. לדוגמה, פעם ביום, בכל שעה או בכל 5 דקות.

  • כוונה בהמתנה שתופעל כשהשעון המעורר יופעל. כשמגדירים התראה שנייה שמשתמשת באותו כוונה בהמתנה, היא מחליפה את ההתראה המקורית.

כדי לבטל PendingIntent(), מעבירים את FLAG_NO_CREATE אל PendingIntent.getService() כדי לקבל מופע של ה-Intent (אם הוא קיים), ואז מעבירים את ה-Intent הזה אל AlarmManager.cancel().

Kotlin

val alarmManager =
    context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
val pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE)
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent)
}

Java

AlarmManager alarmManager =
    (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent);
}

בחירת סוג ההתראה

אחד מהשיקולים הראשונים בשימוש בהתראה חוזרת הוא איזה סוג היא צריכה להיות.

יש שני סוגים כלליים של שעונים לשעון מעורר: 'זמן חולף בזמן אמת' ו'שעון בזמן אמת' (RTC). הזמן שחלף בזמן אמת משתמש ב'זמן מאז הפעלת המערכת' בתור נקודת ייחוס, והשעון בזמן אמת משתמש בשעון UTC (שעון הקיר). כלומר, זמן חולף בזמן אמת מתאים להגדרת התראה על סמך הזמן שחלף (לדוגמה, התראה שתופעל כל 30 שניות), כי הוא לא מושפע מחגורת זמן או מיקום גיאוגרפי. סוג השעון בזמן אמת מתאים יותר להתראות שמבוססות על האזור הנוכחי.

לשני הסוגים יש גרסה של 'הפעלה', שמפעילה את המעבד של המכשיר אם המסך כבוי. כך מובטח שההתראה תופעל בשעה שתזמנתם. האפשרות הזו שימושית אם יש לאפליקציה שלכם תלות בזמן. לדוגמה, אם יש לו חלון זמן מוגבל לביצוע פעולה מסוימת. אם לא משתמשים בגרסה של השעון המעורר שמעוררת אתכם, כל ההתראות החוזרות יופעלו בפעם הבאה שהמכשיר יתעורר.

אם אתם רוצים שההתראה תופעל פשוט במרווח זמן מסוים (לדוגמה, כל חצי שעה), תוכלו להשתמש באחד מהסוגים של זמן חולף בזמן אמת. באופן כללי, זו הבחירה הטובה יותר.

אם אתם רוצים שההתראה תופעל בשעה מסוימת ביום, תוכלו לבחור באחד מסוגי השעון מבוססי-הזמן האמיתיים. עם זאת, חשוב לזכור שלגישה הזו יכולים להיות כמה חסרונות. יכול להיות שהאפליקציה לא תתאים היטב למיקומים אחרים, ואם המשתמש ישנה את הגדרת השעון במכשיר, זה עלול לגרום להתנהגות בלתי צפויה באפליקציה. בנוסף, שימוש בתריס שעון בזמן אמת לא מתאים להתאמה לעומס, כפי שצוין למעלה. אם אפשר, מומלץ להשתמש בהתראה מסוג 'זמן חולף בפועל'.

זו רשימת הסוגים:

  • ELAPSED_REALTIME: הפעלת ה-intent בהמתנה על סמך משך הזמן שחלף מאז הפעלת המכשיר, אבל בלי להעיר את המכשיר. משך הזמן שחלף כולל את כל הזמן שבו המכשיר היה במצב שינה.

  • ELAPSED_REALTIME_WAKEUP: הפעלת המכשיר והפעלת ה-intent בהמתנה לאחר שתקופת הזמן שצוינה חולפת מאז הפעלת המכשיר.

  • RTC: הפעלת ה-intent בהמתנה בשעה שצוינה, אבל לא הפעלת המכשיר.

  • RTC_WAKEUP: הפעלת המכשיר כדי להפעיל את ה-intent בהמתנה בשעה שצוינה.

דוגמאות להתראות על זמן חולף בזמן אמת

ריכזנו כאן כמה דוגמאות לשימוש ב-ELAPSED_REALTIME_WAKEUP

מפעילים את המכשיר כדי שהשעון המעורר יצלצל תוך 30 דקות, וכל 30 דקות לאחר מכן:

Kotlin

// Hopefully your alarm will have a lower frequency than this!
alarmMgr?.setInexactRepeating(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR,
        alarmIntent
)

Java

// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);

מפעילים את המכשיר כדי להפעיל התראה חד-פעמית (לא חוזרת) בעוד דקה:

Kotlin

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

alarmMgr?.set(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + 60 * 1000,
        alarmIntent
)

Java

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() +
        60 * 1000, alarmIntent);

דוגמאות להתראות שעון בזמן אמת

ריכזנו כאן כמה דוגמאות לשימוש ב-RTC_WAKEUP.

מפעילים את המכשיר כדי להפעיל את ההתראה בסביבות השעה 14:00, וחוזר חלילה פעם ביום באותה שעה:

Kotlin

// Set the alarm to start at approximately 2:00 p.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    set(Calendar.HOUR_OF_DAY, 14)
}

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr?.setInexactRepeating(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        AlarmManager.INTERVAL_DAY,
        alarmIntent
)

Java

// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        AlarmManager.INTERVAL_DAY, alarmIntent);

מפעילים את המכשיר כדי שהשעון המעורר יפעל בדיוק בשעה 8:30, וכל 20 דקות לאחר מכן:

Kotlin

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

// Set the alarm to start at 8:30 a.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    set(Calendar.HOUR_OF_DAY, 8)
    set(Calendar.MINUTE, 30)
}

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr?.setRepeating(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        1000 * 60 * 20,
        alarmIntent
)

Java

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

// Set the alarm to start at 8:30 a.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        1000 * 60 * 20, alarmIntent);

קובעים את רמת הדיוק של ההתראה

כפי שמתואר למעלה, בחירת סוג ההתראה היא לרוב השלב הראשון ביצירת התראה. הבדלים נוספים הם מידת הדיוק של ההתראה. לרוב האפליקציות, האפשרות setInexactRepeating() היא הבחירה הנכונה. כשמשתמשים בשיטה הזו, Android מסנכרן כמה אזעקות חוזרות לא מדויקות ומפעיל אותן בו-זמנית. כך תוכלו להפחית את הלחץ על הסוללה.

אם הדבר אפשרי, מומלץ להימנע משימוש בהתראות מדויקות. עם זאת, באפליקציות נדירות שיש להן דרישות זמן קפדניות, אפשר להגדיר שעון מעורר מדויק באמצעות קריאה ל-setRepeating().

כשמשתמשים ב-setInexactRepeating(), אי אפשר לציין מרווח זמן מותאם אישית כמו שאפשר לעשות עם setRepeating(). צריך להשתמש באחד מקבועי המרווחים, כמו INTERVAL_FIFTEEN_MINUTES,‏ INTERVAL_DAY וכן הלאה. הרשימה המלאה מופיעה במאמר AlarmManager.

ביטול התראה

בהתאם לאפליקציה, כדאי לכלול את האפשרות לבטל את ההתראה. כדי לבטל התראה, קוראים ל-cancel() ב-Alarm Manager ומעבירים את הערך של PendingIntent שרוצים להפסיק להפעיל. לדוגמה:

Kotlin

// If the alarm has been set, cancel it.
alarmMgr?.cancel(alarmIntent)

Java

// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}

הפעלת התראה כשהמכשיר מופעל מחדש

כברירת מחדל, כל ההתראות מבוטלות כשמכשיר מושבת. כדי למנוע מצב כזה, אפשר לתכנן את האפליקציה כך שתפעיל מחדש באופן אוטומטי אזעקה חוזרת אם המשתמש מפעיל מחדש את המכשיר. כך תוכלו לוודא שה-AlarmManager ימשיך לבצע את המשימה שלו בלי שהמשתמש יצטרך להפעיל מחדש את ההתראה באופן ידני.

אלה השלבים:

  1. מגדירים את ההרשאה RECEIVE_BOOT_COMPLETED במניפסט של האפליקציה. כך האפליקציה תוכל לקבל את ההודעה ACTION_BOOT_COMPLETED שמשודרת אחרי שהמערכת מסיימת את האתחול (הפעולה הזו פועלת רק אם המשתמש כבר הפעיל את האפליקציה לפחות פעם אחת):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. מטמיעים את BroadcastReceiver כדי לקבל את השידור:

    Kotlin

    class SampleBootReceiver : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "android.intent.action.BOOT_COMPLETED") {
                // Set the alarm here.
            }
        }
    }
    

    Java

    public class SampleBootReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
                // Set the alarm here.
            }
        }
    }
    
  3. מוסיפים את המקלט לקובץ המניפסט של האפליקציה באמצעות מסנן Intent שמסנן את הפעולה ACTION_BOOT_COMPLETED:

    <receiver android:name=".SampleBootReceiver"
            android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>

    שימו לב שבמניפסט, מקלט האתחול מוגדר כ-android:enabled="false". המשמעות היא שהמקבל לא יקרא אלא אם האפליקציה תפעיל אותו באופן מפורש. כך אפשר למנוע קריאה לא הכרחית למקלט האתחול. אפשר להפעיל מקלט (לדוגמה, אם המשתמש מגדיר שעון מעורר) באופן הבא:

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
    )
    

    Java

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);
    

    אחרי הפעלת המקלט באופן הזה, הוא יישאר מופעל גם אם המשתמש יפעיל מחדש את המכשיר. במילים אחרות, הפעלה פרוגרמטית של המקלט מבטלת את ההגדרה במניפסט, גם אחרי הפעלות מחדש. המקלט יישאר מופעל עד שהאפליקציה תשבית אותו. אפשר להשבית מקלט (לדוגמה, אם המשתמש מבטל אזעקה) באופן הבא:

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
    )
    

    Java

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);
    

הפעלת ההתראות כשהמכשיר במצב שינה

במכשירים עם Android 6.0 (רמת API ‏23) יש תמיכה במצב Doze, שעוזר להאריך את חיי הסוללה של המכשיר. ההתראות לא מופעלות כשהמכשיר נמצא במצב שינה. כל ההתראות המתוזמנות מושהות עד שהמכשיר יוצא ממצב שינה. אם אתם צריכים להשלים משימות גם כשהמכשיר לא פעיל, יש כמה אפשרויות:

שיטות מומלצות

לכל בחירה שתעשו בתכנון ההתראה החוזרת יכולות להיות השלכות על האופן שבו האפליקציה משתמשת במשאבי המערכת (או מנצלת אותם לרעה). לדוגמה, נניח שיש אפליקציה פופולרית שמסתנכרנת עם שרת. אם פעולת הסנכרון מבוססת על השעון, וכל מופע של האפליקציה מסתנכרן בשעה 23:00, העומס על השרת עלול לגרום לזמן אחזור ארוך או אפילו להתקפת מניעת שירות (DoS). מומלץ לפעול לפי השיטות המומלצות הבאות בשימוש בהתראות:

  • מוסיפים אקראיות (רעידות) לכל בקשות הרשת שמופעלות כתוצאה מהתראה חוזרת:

    • לבצע משימות מקומיות כשהתראה מופעלת. 'עבודה מקומית' היא כל פעולה שלא מפעילה שרת או שמחייבת את הנתונים מהשרת.

    • במקביל, מגדירים את ההתראה שמכילה את הבקשות מהרשתות שתופעל בתקופה אקראית כלשהי.

  • כדאי להפחית את תדירות ההתראות למינימום.

  • לא להעיר את המכשיר ללא צורך (ההתנהגות הזו נקבעת לפי סוג ההתראה, כפי שמתואר בקטע בחירת סוג התראה).

  • אל תגדירו שעון מעורר עם זמן הפעלה מדויק יותר מהנדרש.

    משתמשים ב-setInexactRepeating() במקום ב-setRepeating(). כשמשתמשים ב-setInexactRepeating(), Android מסנכרנת אזעקות חוזרות מכמה אפליקציות ומפעילה אותן באותו זמן. כך מופחת מספר הפעמים הכולל שהמערכת צריכה להעיר את המכשיר, וכתוצאה מכך מופחת השימוש בסוללה. החל מגרסה Android 4.4 (רמת API 19), כל ההתראות החוזרות הן התראות לא מדויקות. חשוב לזכור ש-setInexactRepeating() הוא שיפור לעומת setRepeating(), אבל הוא עדיין עלול להעמיס על השרת אם כל מופע של האפליקציה יפנה לשרת בערך באותו זמן. לכן, לבקשות רשת, מוסיפים קצת אקראיות להתראות, כפי שצוין למעלה.

  • אם אפשר, כדאי להימנע מהגדרת ההתראה לפי השעון.

    התראות חוזרות שמבוססות על זמן טריגר מדויק לא מתאימות להתאמה לעומס. אם אפשר, כדאי להשתמש ב-ELAPSED_REALTIME. סוגי ההתראות השונים מתוארים בהרחבה בקטע הבא.