Why alarmmanager not exactly repeats an event android - android

Please help me. Why does AlarmManager not exactly repeats an event when the repetition period of more than one day?
Here is my code to run AlarmManager. The variable time_period contains the following value 60*1000*60*24*7 which is equal to 7 days. In the end, if I change the date on your phone, the event is triggered by 6-4-7-7-7-7 days.
This can be seen in the logs of the application (See link http://prntscr.com/7kdqbw ) Thanks in advance for your reply.
Intent notification = new Intent(this , ServiceReminders.class);
notification.putExtra("backup", "backup");
AlarmManager alarmManagerBackup = (AlarmManager)getSystemService(ALARM_SERVICE);
PendingIntent pibackup = PendingIntent.getService(this, 3, notification, 10);
if (sdkVersion < 19) {
alarmManagerBackup.setRepeating(AlarmManager.RTC_WAKEUP, 0, time_period, pibackup);
}
else if (sdkVersion >= 19) {
alarmManagerBackup.setInexactRepeating(AlarmManager.RTC_WAKEUP, 0, time_period, pibackup);
}
Log.d("ServiceManagerNotification", "AlarmBackup sdkVersion = "+sdkVersion);

You are explicitly leveraging the inexact alarms by calling setInexactRepeating(). Unsurprisingly, this results in your alarms being set at inexact intervals.
The problem is further compounded by the fact that you are supplying a custom period. If you do not use one of the pre-defined intervals, then the framework will simply call setRepeating() using your interval instead of using setInexactRepeating().
From the documentation for the intervalMillis parameter:
interval in milliseconds between subsequent repeats of the alarm. Prior to API 19, if this is one of INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_HALF_DAY, or INTERVAL_DAY then the alarm will be phase-aligned with other alarms to reduce the number of wakeups. Otherwise, the alarm will be set as though the application had called setRepeating(int, long, long, PendingIntent). As of API 19, all repeating alarms will be inexact and subject to batching with other alarms regardless of their stated repeat interval.
In the end, regardless of how you set this alarm, it will be inexact if you set it as a repeating alarm and there isn't a whole lot you can do about it.
If you need more precision, you should use either setWindow() or setExact() and set the next alarm every time your alarm triggers. Although if you are only performing an action once a week, it is likely that in the end you don't need that precision.

Related

setExactAndAllowWhileIdle is almost triggered exactly

I searched the Internet for an answer but have not found anything.
I wrote an app where every 17 minute an SMS must be sent ( every 17 minute means: 10:17:00 and not at 10:17:49 )
Therefore, I use an AlarmManager with setExactAndAllowWhileIdle, and AlarmManager.RTC_WAKEUP.
Long whenToFireOff = treeMapInstance.getFirstEntryInTreeMap().getKey();
Calendar alarmCal = Calendar.getInstance();
alarmCal.set(Calendar.HOUR_OF_DAY, treeMapInstance.convertMillisecondsToHour(whenToFireOff));
alarmCal.set(Calendar.MINUTE, treeMapInstance.convertMillisecondsToMinutes(whenToFireOff));
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmCal.getTimeInMillis(), pi);
However, it gets always triggered round about 10:17:49, and the next scheduled alarm also at 10:34:49, and so on.
I calculated my next alarm correctly. I am absolutely 100% sure :)
Is setExactAndAllowWhileIdle not as exactly as it is written in the documentation?
Thanks

Android Alarms too early

I'm using android studio to develop an application that would retrieve the time information from the database and would set an alarm to prompt the user that it's time to drink the medicine, my problem is that the alarm goes on too early
for example the retrieved time is 12:50 AM and the current time is 12:40 AM
even though there's a 10 minutes difference the alarm goes off right away
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm");
try {
Calendar Cnow = Calendar.getInstance();
long now=Cnow.getTimeInMillis();
Calendar time=Calendar.getInstance();
time.setTimeInMillis(0);
Date dTime=sdf.parse(strAlarmDate + " " + strTime1);
//example strAlarmDate="2015-09-27" and strTime1="12:50 AM" and now="12:40 AM" in millis
//dTime="...... 2015-09-27 00:50"
time.setTime(dTime);
//Date dNow=now.getTime();
//time.setTime(date);
//long trigger=time.getTimeInMillis()-now.getTimeInMillis();
long trigger=time.getTimeInMillis()-now;
if(trigger>0) {
ctr++;
Intent i = new Intent(Login.this, AlarmReceiver.class);
i.putExtra("message", strMedname);
i.putExtra("line", strLine);
final int _id = (int) System.currentTimeMillis();
PendingIntent pi = PendingIntent.getActivity(Login.this, _id, i, 0);
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
// am.set(AlarmManager.RTC_WAKEUP, trigger, pi);
// am.setExact(AlarmManager.RTC_WAKEUP, trigger, pi);
am.set(AlarmManager.RTC_WAKEUP, trigger, pi);
}
}catch(ParseException ex)
{
ex.printStackTrace();
}
The problem is that you set the alarm to go off at time trigger which is the time minus the current time.
You should pass time.getTimeInMillis() instead.
So replace the line with
am.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pi);
}
Bas van Stein is correct. AlarmManager uses an absolute time: milliseconds since epoch, January 1, 1970. You are attempting to set it to a relative time: milliseconds from the time you are setting the alarm. AlarmManager interprets that as being some time very close to epoch, around January 1, 1970, at 12:10AM. Since that time is long since past, the alarm triggers immediately.
The solution is simply to use time.getTimeInMillis() in set instead of trigger.
Some other notes for doing this kind of work, since your app is similar in intention to mine:
Most alarms since API 19 will be inexact, as Frank N. Stein pointed out. The degree of this inexactness depends on implementation and also how far in the future the alarm is created. For something like medicine which is probably at least daily, in all of my testing the alarm has fired within a minute of the intended time.
You are using the current time as the requestCode in your PendingIntent. By setting this to a number that is meaningful to your program and storing that value, you can later update or cancel this alarm by recreating the same PendingIntent.
From API level 23 and forward, urgent alarms like medication alarms should use setAndAllowWhileIdle() to ensure that their alarm goes off during low power idle states. I do not yet know if using set with RTC_WAKEUP will be sufficient to ensure this behavior.
From the official docs:
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

Multiple Alarms, Few Works and Few does not

stuck around into a problem with
AlarmManager
I developed a method which adds two alarms into an AlarmManager Array. My method given below runs on a button click and adds as many as 10 alarms in the AlarmManager Array two per click.
My method code is given below.
public void stupidAlarm()
{
stupidPendingIntentOne = PendingIntent.getBroadcast(context, listItemClickedPosition, stupidIntentOne, PendingIntent.FLAG_UPDATE_CURRENT);
stupidPendingIntentTwo = PendingIntent.getBroadcast(context, listItemClickedPosition+5, stupidIntentTwo, PendingIntent.FLAG_UPDATE_CURRENT);
stupidAlarm[listItemClickedPosition]= (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
stupidAlarm[listItemClickedPosition+5]= (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmOneTime = settings.getString(AlarmOneTime, null);
alarmTwoTime = settings.getString(AlarmTwoTime, null);
try
{
OneHr = Integer.parseInt(muteTime.substring(0, 2));
OneMin = Integer.parseInt(muteTime.substring(2, 4));
TwoHr = Integer.parseInt(ringerTime.substring(0, 2));
TwoMin = Integer.parseInt(ringerTime.substring(2, 4));
}
catch(Exception ex)
{
Toast.makeText(context, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
stupidCalOne.set(2015, Calendar.MAY, 2);
stupidCalOne.set(Calendar.HOUR_OF_DAY, OneHr);
stupidCalOne.set(Calendar.MINUTE, OneMin);
stupidCalOne.set(Calendar.SECOND, 0);
stupidCalOne.set(Calendar.MILLISECOND, 0);
stupidCalTwo.set(2015, Calendar.MAY, 2);
stupidCalTwo.set(Calendar.HOUR_OF_DAY, TwoHr);
stupidCalTwo.set(Calendar.MINUTE, TwoMin);
stupidCalTwo.set(Calendar.SECOND, 0);
stupidCalTwo.set(Calendar.MILLISECOND, 0);
stupidAlarm[listItemClickedPosition].set(AlarmManager.RTC_WAKEUP, stupidCalOne.getTimeInMillis(), stupidPendingIntentOne);
stupidAlarm[listItemClickedPosition+5].set(AlarmManager.RTC_WAKEUP, stupidCalTwo.getTimeInMillis(), stupidPendingIntentTwo);
}
But the problem is out of 10 Alarms created some works and some does not!
following information may be helpful in this context
AlarmOne 1047Hrs works
AlarmTwo 1048Hrs works
AlarmThree 1049Hrs does not work
AlarmFour 1050Hrs works twice
AlarmFive 1051Hrs does not work
AlarmSix 1052Hrs does not work
AlarmSeven 1053Hrs works thrice
AlarmEight 1054Hrs works
AlarmNine 1055Hrs does not work
AlarmTen 1056Hrs works twice
My declaration of Calendar, Intent, PendingIntent and AlarmManagerArray
//for stupid alarm
public Calendar stupidCalOne;
public Calendar stupidCalTwo;
public Intent stupidIntentOne;
public Intent stupidIntentTwo;
public PendingIntent stupidPendingIntentOne;
public PendingIntent stupidPendingIntentTwo;
public AlarmManager[] stupidAlarm;
My assignments in onCreate method
//for stupid alarm
stupidCalOne = new GregorianCalendar();
stupidCalTwo = new GregorianCalendar();
stupidIntentOne = new Intent(context, OneAlarmReceiver.class);
stupidIntentTwo = new Intent(context, TwoAlarmReceiver.class);
stupidAlarm = new AlarmManager[10];
Any help will be highly appreciated, thanks in advance
The OS is allowed to batch Alarms.
The docs for AlarmManager.set state:
Note: Beginning in API 19, the trigger time passed to this method is treated as inexact: the alarm will not be delivered before this time, but may be deferred and delivered some time later. The OS will use this policy in order to "batch" alarms together across the entire system, minimizing the number of times the device needs to "wake up" and minimizing battery use. In general, alarms scheduled in the near future will not be deferred as long as alarms scheduled far in the future.
And that is why some times are skipped and then fire a minute later along with another alarm.
I suspect the further apart they are, the less likely the system would be to batch them, but you still can't guarantee alarm time with this.
It goes on:
With the new batching policy, delivery ordering guarantees are not as strong as they were previously. If the application sets multiple alarms, it is possible that these alarms' actual delivery ordering may not match the order of their requested delivery times. If your application has strong ordering requirements there are other APIs that you can use to get the necessary behavior; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent).
So use setWindow or setExact. but note with setExact:
Note: only alarms for which there is a strong demand for exact-time delivery (such as an alarm clock ringing at the requested time) should be scheduled as exact. Applications are strongly discouraged from using exact alarms unnecessarily as they reduce the OS's ability to minimize battery use.

Alarmmanager - Fire alarm on top of every minute

I am trying to fire an Alarm on top of every minute. But as for some reason it doesn't want to work. It is for an Widget Clock which should update every minute. For battery reasons i've made an reciever for screen off and on. So my Alarm only fires when the screen is on. The minutes should be syncron with my System clock.
public static void startClockTickAlarm() {
AlarmManager alarmManager = (AlarmManager)_context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 1);
calendar.add(Calendar.HOUR, 1);
alarmManager.setRepeating(AlarmManager.RTC, utcMillisNextMin(), 60000, createClockTickIntent(_context));
}
public static final long utcMillisNextMin() {
Time t = new Time();
t.setToNow();
t.second = 0;
t.minute++;
System.out.println("Next Alarm: " + t.hour + ":" + t.minute + ":" + t.second);
return t.normalize(true);
}
My System.out gives me exactly what it should. For example i enable my widget at 11:30:15 the returning result is 11:31:00 - This means my alarm should firstly fire at 11:31. According to my System Clock, the alarm is 5-15 seconds too late. The seconds which the alarm fires too late are not always the same (between 5 and 15 seconds).
Thanks in advance.
Like #mighter said, API >= 19 if you must use exact timing, use the setExact() API.
if(android.os.Build.VERSION.SDK_INT < 19) {
alarmManager.setRepeating(AlarmManager.RTC, utcMillisNextMin(), 60000, createClockTickIntent(_context));
} else {
alarmManager.setExact(...);
}
There's following statement in docs:
Note: as of API 19, all repeating alarms are inexact. If your
application needs precise delivery times then it must use one-time
exact alarms, rescheduling each time as described above. Legacy
applications whose targetSdkVersion is earlier than API 19 will
continue to have all of their alarms, including repeating alarms,
treated as exact.
If you're running on Android 4.4.4 then this might be the reason.

Android AlarmManager hour alarm running wrong interval

Im trying to set and run an alarm that run every hour, and is set by a few variables so as it will not run instantly, if the time is greater then the 58th minute
The idea is to set it # X hour and 58 minute, so it will run every hour, at the given minute(58).
Calendar calCurrent = Calendar.getInstance();
int time = 58 ;
Calendar calx = Calendar.getInstance();
calx.set(Calendar.MINUTE, time);
calx.set(Calendar.SECOND, 5);
if (calCurrent.get(Calendar.MINUTE) > time) {
calx.add(Calendar.HOUR, +1);
}
System.out.println("Alarm is set to - " + calx.get(Calendar.HOUR)+":"+
calx.get(Calendar.MINUTE));
alarmSwap = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmSwap.setRepeating(AlarmManager.RTC_WAKEUP,
calx.getTimeInMillis(), 60 * 60 * 1000, pintent);
The code works and runs correctly for the 1st instance, then the alarm will for some reason run # 0 minute the following hour.
Timeline looks like
1:23 - Repeating Alarm Set for 1:58 (1 hour intervals)
1:58 - alarm is triggered
3:00 - alarm is triggered
I have no idea why this alarm is being triggered # :00 for the last alarm. It is not being called from anywhere else.
Any help is greatly appreciated.
All alarms are resetting after the hour clocks over the hour-
Calendar calnew = Calendar.getInstance(); calnew.add(Calendar.SECOND, +5);
alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarm.setRepeating(AlarmManager.RTC_WAKEUP, calnew.getTimeInMillis(),900000 , pintent);
Timeline-
1:20 triggered
1:35 triggered
1:50 triggered
2:00 triggered
2:15 triggered
2:30 triggered
From android documentation.
Note: as of API 19, all repeating alarms are inexact. If your
application needs precise delivery times then it must use one-time
exact alarms, rescheduling each time as described above. Legacy
applications whose targetSdkVersion is earlier than API 19 will
continue to have all of their alarms, including repeating alarms,
treated as exact.
repeating alarms are not exact after API 19. This improves androids performance as android groups alarms which are at close interval and wakes system once and finishes all alarms(from other applications also).
If you really want exact alarms the you will have to set normal one time alarm, and then set alarm again in first alarm's call.
Try this code to repeat alarm every hour
alarmSwap.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
calx.getTimeInMillis(),
AlarmManager.INTERVAL_HOUR, pintent);
Hope this will help.You can ask if you have any further queries.
This worked for me to trigger alarm after every 1hour
alarmmgr = (AlarmManager) getSystemService(ALARM_SERVICE);
long interval = 60 * 60 * 1000; // 1 hour
xassert alarmmgr != null;
alarmmgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);

Categories

Resources