I have had several frustrations with setting alarms in Android. I have tried setting repeating/non-repeating alarms and exact/inexact alarms but it does not matter, if the alarm is ever set for a time in the past, it executes as soon as it is set. I have tested this as far back as setting an alarm for 5 hours in the past and is still executes immediately.
For example:
The time is 7 AM and I set an alarm to execute at 2 AM. This is obviously meant for the next time the clock reads 2:00 AM but it does not matter, the alarm goes off at 7 AM, right after it is set.
The code below should select a random time between 1:00 AM and 3:59 AM to set/execute the alarm for the next calendar day and then the logic circles back around to set itself again after execution. The alarm will execute repeatedly, forever.
int randomHour = new Random().nextInt((3 - 1) + 1) + 1;
int randomMinute = new Random().nextInt((59 - 1) + 1) + 1;
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, randomHour);
calendar.set(Calendar.MINUTE, randomMinute);
calendar.set(Calendar.SECOND, 0);
calendar.add(Calendar.DAY_OF_MONTH, 1);
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
Questions:
At what point does Android stop executing alarms in the past?
Is there any way to stop this?
"This is obviously meant for the next time" Does not work for computers, they will do exactly what you tell them to do.
calendar.getTimeInMillis() returns the number of milliseconds since January 1, 1970 at 00:00:00 GMT. You need to specify not just the time but also the date that you want the alarm to go off. Instead you are always calling calendar.add(Calendar.DAY_OF_MONTH, 1); (the first day of the current month)
Related
I am new to android and have problems with setting a repeating alarm. The app is like this: user selects time using a timepicker, and selects several days to set the alarm. I use this code to implement this task:
for(int i=0; i < alarm.getDaysOfTheWeek().size(); i++){
// here is a switch block to assign daysUntilAlarm1
//to a particular day from the list of selected days, like
//daysUntilAlarm1 = Calendar.SUNDAY;
calendar.set(Calendar.DAY_OF_WEEK, daysUntilAlarm1);
calendar.set(Calendar.HOUR_OF_DAY, alarm.getHour()); // hour picked by user
calendar.set(Calendar.MINUTE, alarm.getMinute());
pendingIntent = PendingIntent.getBroadcast(AlarmManagerActivity.this, i, intentToAlarmReceiver, 0);
pendingIntents.add(pendingIntent);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 7 * 24 * 60 * 60 * 1000, pendingIntent);
The problem is when I test alarms, I change the system time to the next alarm day. Everything works fine. But when I change the system time to the past, like last week, the alarm doesn't work. So if user will have to change the time of the device to past, the app will not work. Can anyone help me, please?
I want to trigger a notification each day at a specific time choosen by the user, like 6' / 7' / 8'.
For this, I created a WakefulBroadcastReceiver, that pass to an IntentService to create the notification.
And this is how I setup my AlarmsManager. timeInHours is an integer passed as parameter, between 6 and 12 :
Intent i = new Intent(context, StepCountNotifyBroadcast.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
// Get the next day at timeInHours hours'.
Calendar cal = Calendar.getInstance();
cal.setTime(new Date()); // compute start of the day for the timestamp
cal.set(Calendar.HOUR_OF_DAY, timeInHours);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.AM_PM, Calendar.AM);
if (new Date().getTime() > cal.getTime().getTime())
cal.add(Calendar.DAY_OF_YEAR, 1);
long nextDay = cal.getTime().getTime();
// Setup the alarm.
long timeBetween = AlarmManager.INTERVAL_DAY; // Each day.
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarms.cancel(pi);
alarms.setRepeating(AlarmManager.RTC_WAKEUP, nextDay, timeBetween, pi);
Date nextDayAsDate = new Date(nextDay);
GLog.d("AlarmUtils", "scheduleNotifiation for next date: " + nextDayAsDate.toString());
It works well 50% of the time, but still do crazy things like... Trigger the notification at 2:00 AM ?!
I know the system will not trigger the notification at the specific time I want and this is ok. But here we talk about approximately 18 hours later.
In logs, it seems that my IntentService code is effectively running in the middle of the night in some cases. So that's not an issue with the notification itself.
I can switch this line :
alarms.setRepeating(AlarmManager.RTC_WAKEUP, nextDay, timeBetween, pi);
to another line of code :
alarms.setExact(AlarmManager.RTC_WAKEUP, nextDay, pi);
But this is not good for the battery life I'm afraid.
Now my questions :
Can somebody tell me a reason about the way Android devices works with AlarmsManager ?
Do you find another solution than will not drain battery life and be sure the notification will be triggered in maximum 2 or 3 hours later?
Do you have any ideas, in this particular case, to debug and do code testing without waiting a day or two to detect issues?
Thanks in advance.
After API Level 23, Doze mode was introduced on the Android System to reduce battery consumption. Go through below link:
How to make Alarm Manager work when Android 6.0 in Doze mode?
I have followed the following link https://developer.android.com/training/scheduling/alarms.html.
RTC examples first one, to set an alarm for a specific time on all days. Even after following the same code, the alarm is not triggered at the time it is suppose to get triggered. Instead the notification gets triggered immediately after setting the time which is done with the help of a time picker. Following is my code snippet,
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, NotificationReceiver.class);
PendingIntent intentalarm = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY,4);
calendar.set(Calendar.MINUTE, 30);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, intentalarm);
Instead of setRepeating I also tried setInexactRepeating but there was no luck.I would also like to add that when I changed the
calendar.getTimeInMillis() and used SystemClock.elapsedRealtime() + 120 * 1000 the alarm triggered exactly after 2 minutes from the time it was set.
But when calendar.getTimeInMillis() is being used the intended working does not happen instead immediate triggering occurs.
Would be indeed very helpful if anyone can help me out find a solution.Only for a note, I could learn if alarm is set before current device time the alarm would be triggered immediately but that is not the case here.
NotificationReceiver.class is working fine as it is generated and appears on the title. But the time it appears is the cause of concern.
You are using both setTimeInMillis and hourofday and minute.
If you want your alarm to be triggered at 4:30 just add hourofday and minute.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY,4);
calendar.set(Calendar.MINUTE, 30);`
I could Identify the issue I was facing. I was using a TimePicker with 24 hour format. But I used SimpleDateFormat "hh:mm". What 'h' stands for is as follows "h->Hour in am/pm (1-12) ". So any alarm that I set at AM triggers correctly. When I set a time at PM since I had used 1-12 'h' format, alarm gets set for a AM time and since that time is already passed when compared to the device time the alarm/notification got triggered immediately.The right format to use was "HH:MM" where 'H' stands for "H->Hour in day (0-23)". This resolved my issue.
Checking the TimeinMillis on online epoch time converter helped me identify this issue.Once again thanks for helping me.
I am trying to execute a background process on my android app every day at around 09h10 am. This works fine, but problem is after the first alarm has been fired at 09h10 am, it gets re-fired after 10 - 20 minutes throughout the day. I just want it to fire once a day, and only at that specified time. My code that sets the alarm manager is below:
PendingIntent reviewsPendingIntent = PendingIntent.getBroadcast(this,0,new Intent(this,ReviewReceiver.class),0);
AlarmManager alarmManager = (AlarmManager)(this.getSystemService(Context.ALARM_SERVICE));
Calendar cur_cal = new GregorianCalendar();
cur_cal.setTimeInMillis(System.currentTimeMillis());
Calendar cal = new GregorianCalendar();
cal.set(Calendar.HOUR_OF_DAY, 9);
cal.set(Calendar.MINUTE, 10);
cal.set(Calendar.SECOND, 10);
cal.set(Calendar.MILLISECOND, cur_cal.get(Calendar.MILLISECOND));
long interval = 6000*1440;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(),interval,reviewsPendingIntent);
I have set the interval to 8640000 which is a day(I believe) if not, please advise accordingly. Thank you
1000ms*60s*60m*24h = 86400000 so You missed one 0
You can use
PendingIntent reviewsPendingIntent = PendingIntent.getBroadcast(this,0,new Intent(this,ReviewReceiver.class),PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(),AlarmManager.INTERVAL_DAY,reviewsPendingIntent);
FLAG_CANCEL_CURRENT will prevent the alarm to be set multiple times
AlarmManager.INTERVAL_DAY = 1000 * 60 * 60 * 24
If you keep having some delay, it's because the sleep function is not precise. It's around the time you have set. Try with setExact and reschedule every day, doing the math by hand (initialTime + dayPassed * millsInADay) to have the best approximation.
If what Lindus has posted worked though, just forget it :) but I think that you'll have the same problem.
I have read lots of articles, however I did not find/or just missed an answer on my specific quiestion, it is strange cause I think I am trying to implement a common case.
Well, what I whant is to set alarm to fire everyday except the weekends, so from monday-friday at some specific time.
Currently I do next:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
Intent intent = creating an Intent here
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
as far as I understand next code will fire an alarm on the time I have specified and do it every day, because of AlarmManager.INTERVAL_DAY.
I thought about doing next to accomplish my task:
for(int i = 1; i < 6; i++) {
calendar.add(Calendar.DAY_OF_WEEK, i);
}
But I am not sure, about the correctness of this logic.
Can you please
1. correct me, if I missed something
2. suggest some proper solution or just your thoughts to accomplish my task
Update:
Well, I have thought about next:
what if I
calendar.set(Calendar.DAY_OF_WEEK, 1);
and then
am.setRepeating(AlarmManager.RTC_WAKEUP, date.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 5, pendingIntent);
so as a result I will be setting initial day to Monday and repeat it 5 times, so Monday-Friday, no matter what is the current date, when user is setting an alarm, is it correct or I am missing smth?
Btw, how can I update setRepeating to set it to repeat every week, not only one?
Update1:
I guess I understood my error, by using the above code, I will do some strange things, so the init day is Monday, however the repeat interval is once in 5 days, not every day from Monday-Friday.
It seems that the only solution is to set
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
and in the fire handler, which I have specified in the Intent constructor, check the current day and avoid notification if it is Saturday or Sunday.
...
if(intent.getBooleanExtra(INTENT_NOTIFY, false) && !isWeekend())
showNotification();
...
private boolean isWeekend() {
Calendar calendar = Calendar.getInstance();
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
return (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY);
}
Btw, tell me please, I have set the alarm in repeat mode, for the first time it did fire, then I open emulator settings and manually move date to tomorrow and time back, but no alarm notification is fired, is it smth with emulator or I have some errors in code?