תזמון התראות

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

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

  • הם מאפשרים להפעיל אובייקטים מסוג Intent בזמנים או במרווחי זמן קבועים.

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

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

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

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

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

המפתחים יכולים להיעזר באחריות ה-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 מספק דרך לתזמן תקופת זמן שתלויה בתזמון work. אפשר לספק מרווח זמן של חזרה ו-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 לאובייקט, למשל עם setExact API, ההרשאה 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 שכולל את ACTION_REQUEST_SCHEDULE_EXACT_ALARM פעולת Intent.

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

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

התראה שתוכננה בצורה לא טובה עלולה לרוקן את הסוללה ולהעמיס באופן משמעותי על השרתים. לכן, ב-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() ב-Alert 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 action:

    <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) נמנום למצב הזה, עוזר להאריך את חיי הסוללה של המכשיר. ההתראות לא מופעלות כשהמכשיר נמצא במצב שינה. כל ההתראות המתוזמנות מושהות עד שהמכשיר יוצא ממצב שינה. אם אתם צריכים להשלים משימות גם כשהמכשיר לא פעיל, יש כמה אפשרויות:

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

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

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

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

    • במקביל, צריך לתזמן את ההתראה שמכילה את בקשות הרשת ל לפעול בפרק זמן אקראי.

  • כדאי להקפיד שתדירות ההתראות תהיה מינימלית.

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

  • אל תקפידו ששעת ההפעלה של ההתראה תהיה מדויקת יותר ממה שהיא צריכה להיות.

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

  • אם אפשר, מומלץ להימנע מקביעת שעתוק של השעון המעורר.

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