יום שני, נובמבר 29

Alarms

Alarms\אזעקות- זהו מנגנון לתזמון שליחת intents במערכת.
ה-Alarm לא שייך לאפליקציה, כך שגם אם האפליקציה נסגרה ה-Alarm שהיא הכינה ימשיך לפעול. היכולת לפעול גם כשהאפליקציה סגורה וכשהמכשיר במצב שינה פירושה חיסכון בהספק. מבחינה זו, שימוש ב-Alarm עדיף מתזמון תהליכים ע"י אפליקציה + טיימר. ה-Alarm שולח intent בזמן הקבוע מראש.  הintent יכול להיות מסוג Broadcast ואז יטופל במסגרת ה-broadcast receiver, אותו כבר סקרנו, אך כמובן יכול להפעיל ישירות Activity אחר. אגב, בדוגמא שנסקור בהמשך, נשתמש ב-intent מסוג broadcast, שלאחר מכן יצור intent נוסף, מסוג explicit שיפעיל אפליקציה אחרת.
מנגנון ה-Alarm מטופל ע"י ה-AlarmManager class. תהליך יצירת ה-Alarm דומה לזה של ה-notification ואפילו פשוט יותר.

נסביר את תהליך יצירת ה-Alarm בפרוט ובשלבים תוך כדי הצגת דוגמא.

הדוגמא כוללת class אחד בשם MyClass משם תתבצע הכנת ה-Alarm ו-subclass של BroadcastReceiver שיטפל ב-intent.


  • ה-Intent שיוצמד ל-Alarm יהיה מסוג Implicit וישלח כ-broadcast, כך שהוא יטופל ע"י ה-BroadcastFilter. (היה ניתן לשלוח גם intent מסוג Explicit ולהפעיל Activity אחר באופן ישיר). 
  • ה-BroadcastFilter ישלח Intent נוסף, הפעם Explicit Intent שיפעיל את ה-MyNotification -  באפליקציה אחרת.
  • האפליקציה תכלול מסך אחד, בנוסף למסך של האפליקציה Notification שתופעל ע"י Intent.
נראה את המסך הראשי:



ומשם, ה-Alarm יפעיל את המסך  של MyNotification:




 לא נרחיב בהסברים על יצירת ה-UI ובעיקר לא על ה-Notification עליו כאמור כבר דנו.

לעבודה:

שלב 1:  יצירת אובייקט ה-Alarm.

       alarms = (AlarmManager)getSystemService(Context.ALARM_SERVICE);

האובייקט הוא מסוג AlarmManager שהוא הישות המרכזית המטפלת ב-Alarms במערכת, לכן  כמו עם ה-NotificationManager,  לא ניצור עותק שלו ע"י יצירת instance אלא נשתמש בו בעזרת המתודה getSystemService עם הפרמטר ALARM_SERVICE.

שלב 2: הגדרת ה-Intent של ה-Alarm. זהו ה-Intent שיתבצע כשה-Alarm יופעל.



  1.   String ALARM_ACTION = "com.ahs.androheb.notifications.ALARM_ACTION";
  2.   Intent mIntent =  new Intent(ALARM_ACTION);
  3.   mPendingIntent = PendingIntent.getBroadcast(this, 0, mIntent, 0);

  • שורה 3:המטרה היא לצור אובייקט PendingIntent, שהוא intent עם מעטפת נוספת, שנועד להפעלה ע"י מודול אחר.
  • שורה 2: ה-Intent הוא מסוג Implicit כשה-action שלו הוא: com.ahs.androheb.notifications.ALARM_ACTION.
  • למה יש לו שם כ"כ ארוך? הוספנו את שם ה-package כקידומת כדי למנוע כפילות שמות שעלולה לבלבל את ה-Broadcast Filter.
שלב 3:
היות שברצוננו לטפל ב-intent ע"י ה-broadcastReceiver, הגדרנו receiver בקובץ ה-manifest והגדרנו פילטר ב-java:

  1.         registerReceiver(
                    new MyBroadcastReceiver(),
                    new IntentFilter(ALARM_ACTION));
     

הערה: גם את הפילטר עצמו היה אפשר להגדיר במניפסט כמו שהסברנו בפוסט על ה-broadcast Receiver.

שלב 4:
כל שנותר הוא להגדיר delay ולהפעיל את ה-Alarm.
ה-delay אצלנו מוכנס אינטראקטיבית דרך ה-UI : ראה בקבצי המקור. בכל אופן, פרמטר ה-delay נמדד במילי שניות.

..שיגור ה-Alarm:

 alarms.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, mPendingIntent);
המתודה set הנ"ל מקבלת 3 פרמטרים:

  1. סוג ה-Alarm
  2. ה-delay
  3. ה-pendingIntent שיופעל
פרוט על הפרמטרים הנ"ל:

פרמטר 1: סוג ה-Alarm
Alarm Type - קיימים 4 סוגים אפשריים:
  • RTC_WAKEUP
  • RTC
  • ELAPSED_REALTIME
  • ELAPSES_REALTIME_WAKEUP
השניים הראשוניים (RTCxxx), קובעים שה-Alarm יופעל בהתאם לזמן האמיתי: RTC = Real Time Clock.
השניים האחרונים (ELAPSEDxxx), מתיחסים לזמן שחלף מאז ה-boot.

ה-"WAKEUP" יגרום להפעלת ה-Alarm גם אם המערכת בתרדמה.

פרמטר 2: ה-delay

הזמן (במילישניות): מדובר בזמן האמיתי או בזמן שחלף מה-boot, בהתאם לפרמטר ה-Alarm Type.

פרמטר 3: ה-Pending Intent -אותו יצרנו קודם.


Alarm עם נודניק
קיימת האפשרות ליצור Alarm חוזר (נודניק) במרווחי זמן קבועים מראש. במקום להשתמש במתודה set (ראה alarm.set כאן למעלה) השתמש ב- setRepeating או setInexactRepeating.

alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, intervalTime, mPendingIntent);

הפרמטר שנוסף כאן הוא ה-intervalTime.

המתודה הנוספת להפעלת נודניק היא setInexactRepeating, שמאפשרת קביעת זמן מחזור לא מדויק. "זמן מחזור לא מדויק" מאפשר חיבור של כמה Alarms וביצועם סימולטנית בארוע אחד. היתרון - פחות פעמים להעיר את המכשיר = חיסכון באנרגיה.
דוגמא:


 alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + delay, AlarmManager.INTERVAL_DAY, mPendingIntent);
כאן האינטרוול שנקבע הוא של יום.
סוגי האינטרולים האפשריים:

INTERVAL_DAY

INTERVAL_FIFTEEN_MINUTES

INTERVAL_HALF_DAY

INTERVAL_HALF_HOUR

INTERVAL_HOUR
סיימנו עם הפעלת ה-Alarm.
ביטול ה-Alarm:
alarms.cancel(mPendingIntent);


בדוגמא המצורפת, פקודת הביטול מתבצעת ב-onClick callback של כפתור הביטול.


אחזור על הערה שמופיעה באתר של אנדרואיד: אם ה-Alarm יפעיל Service, קיימת אפשרות שהמכשיר יחזור לתרדמת לפני שה-Service סיים את הביצוע. אפשר למנוע זאת בעזרת במנגנוני wakeLock. נדבר על מנגנונים אלה בפוסט על ה-powerManager.


10 תגובות:

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

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

    אם למישהו יש פתרון יותר יצירתי אשמח לתגובות .

    השבמחק
  2. הי לאוניד,
    כדי להפעיל Alarms רבים בבת אחת, צריך לתת מזהה שונה (request code) ל-pending intent. דוגמא:
    mPendingIntent = PendingIntent.getBroadcast(this, uniqueCode, mIntent, 0

    uniqueCode - מזהה ייחודי עבור כל Alarm.

    השבמחק
  3. ואז אפשר להפעיל כמה pending intent , בכמה ALARMS שונים ?

    זה יכול להיות index רץ , כלומר זה חייב להיות איזה מספר יחודי רק לACTIVETY שלי או שזה יכול להיות כל מספר מ 0 עד 999999 ?

    עוד שאלה בהקשר , זה יעבוד גם אם המכשיר מכובה , או בוצע לו RESTART , או שצריך להפעיל SERVICE שבאיתחול יפעיל את הALARMS ?

    השבמחק
  4. כן, אפשר להפעיל הרבה Alarms.
    האינדקס אכן צריך להיות יחודי, אחרת פעולת ה-set תדרוס את ה-Alarm הקודם.
    תחום המספרים עבור האינדקס הוא 31-1^2+/-.
    ה-Alarm יתנקה בכיבוי או Restart אבל יפעל כשהמכשיר ב-asleep.

    השבמחק
  5. כן, אפשר להפעיל הרבה Alarms.
    האינדקס אכן צריך להיות יחודי, אחרת פעולת ה-set תדרוס את ה-Alarm הקודם.
    תחום המספרים עבור האינדקס הוא בין 31-1^2+ ל- 31^2-
    ה-Alarm יתנקה בכיבוי או Restart אבל יפעל כשהמכשיר ב-asleep.

    השבמחק
  6. יש אפשרות להשאיר את הALARM דלוק כאשר הטלפון מכובה ?
    ושלא יתנקה ב RESTART ?

    השבמחק
  7. כמובן. בנוקיות הישנות :-). אתה מוזמן לבדוק ולעדכן.

    השבמחק
  8. אחרי בדיקה הALARM מתאפס אחרי איתחול , יש צורך להפעיל SERVICE אם האיתחול כדי שידרוך את הALARM שוב.

    השבמחק
  9. הי אולי תוכל לעזור לי, משום מה אחרי כמה ימים, ALARM שיצרתי לא פועל (פעל במשך כשבוע כל 5 דקות בערך
    יש לך אולי מושג מה יכול לגרום לבעיה כזו?

    תודה

    השבמחק
  10. לאוניד, לדעתי אם אתה רוצה שה ALARM יעבוד כשאתה מדליק את המכשיר
    פשוט תבנה Brodcast Reciever (בXML) ותגדיר שהוא יעלה ב BOOT של המכשיר,
    וכאשר הוא יעלה תבצע קריאה לאקטיביטי שבו מוגדר ה ALARM

    השבמחק