תזמון התראות

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

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

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

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

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

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

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

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

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

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

אם האפליקציה משתמשת ב-set(), setInexactRepeating(), או setAndAllowWhileIdle(), ההתראה אף פעם לא מופעלת לפני שעת הטריגר שסופקה.

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

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

אם האפליקציה שולחת קריאה למספר 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 דקות.

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

כדי לבטל PendingIntent(), צריך FLAG_NO_CREATE אל PendingIntent.getService() כדי לקבל מופע של הכוונה (אם קיים), ואז להעביר את הכוונה הזו 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 אם שאפשר. ההתראה השונה מתוארים בפירוט נוסף בקטע הבא.