I have an alarm which I can schedule to go off at a certain time. The thing is, when I shedule it into the future, it works at exactly the minute I set it for. It works as it should. But the problem is, if I schedule it in the past, it goes off immediately.
For example, if it is now 3:30pm and I schedule it for 3:35pm, it fires at 3:35pm. But if it is 3:30pm and I schedule it for 3:25pm, it fires immediately since it is in the past.
What I want it to do is, if it is int he past, just ignore it until the interval time passes.
Here is the code:
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(context, ApplicationClass.AlertNotifyID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
long milliSeconds24Hours = 86400000; //86400000 which is 24 hours in milliseconds
am.setRepeating(AlarmManager.RTC_WAKEUP, GetNotificationTime(context), milliSeconds24Hours, sender);
You need to get it to check if the scheduled time is in the past, and if so set your alarm to start the next day.
Related
I am attempting to create a sample alarm application using AlarmManager. However, the alarm goes off at different times even though I have set a specific time for it to be triggered.
Setting the alarm:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 18); // trigger at 6 PM
Intent notifyIntent = new Intent(context, CheckupAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast
(context, 100, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
android.app.AlarmManager alarmManager = (android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
alarmManager.setInexactRepeating(android.app.AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
android.app.AlarmManager.INTERVAL_DAY, pendingIntent);
}
Manifest:
<receiver
android:name=".notifications.CheckupAlarmReceiver"
android:enabled="true"
android:exported="false" />
To re-iterate, the alarm works fine. It just fires at the wrong time. Is the Calendar instance not taking the time zone in to consideration? What am I doing wrong here?
Your are setting setInexactRepeating() which as its name says, it could not be fired at the exact time you specified. This is an optimization so the Operating System tries to get more than one alarm which should fire at similar times to fire all of them at the same time.
Instead, you can use void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation). See documentation.
Example:
alarmManager.setExactAndAllowWhileIdle(android.app.AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
As its recommended, you shouldn't use a repeating alarm with exact times. Instead, you can wait until the exact alarm fires and then schedule another alarm for the next day.
For API lower than 23, you can use void setExact(int type, long triggerAtMillis, PendingIntent operation). And for API lower than 19, you can use void setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation) with the expected exact firing as always.
I want to trigger a daily alarm in my application. I can see the alarm being triggered daily at the correct time for 2 or 3 days but it does not trigger after that. For example if I set alarm to trigger at 08:00 AM, it will trigger at 8 AM daily for 2 or 3 days and after that there is no alarm triggered. There is no app crashing or anything, it simply does not trigger. I have a BroadcastReceiver registered (in AndroidManifest.xml) for this alarm and i can see logs being printed daily at the correct time but only for 2 or 3 days. After that there is no activity and the app just seems to die down.
Please find my code below :
final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
final long intervalDay = 60*60*24*1000L;
final long alarmTime = calendar.getTimeInMillis();
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime, intervalDay, pendingIntent);
I have also used alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime, AlarmManager.INTERVAL_DAY, pendingIntent); but it did not make any difference (didnt expect it to make any though).
I do not want to use alarmManager.setInexactRepeating() as it does not trigger the alarm at exact time but there is slight delay.
Any help appreciated !!
Thanks.
That's because android cannot hold the alarm content for more than 2-3 days. Though there is no sure shot solution that i know.
I fixed it by cancelling and resetting alarm everytime alarm is triggered.
Something like this.
Instead of using setRepeat use set or setExact to trigger for once:
if(android.os.Build.VERSION.SDK_INT<Build.VERSION_CODES.KITKAT) {
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmtime, pendingIntent);
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, alarmtime, pendingIntent);
}
Then in onRecieve() method of your alarmReciever after performing your task, reset the alarm again for next followed by cancelling all pending intents:
PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), reminderModal.get_remindID(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
pendingIntent.cancel();
Hope it helps.
I am creating a clock application that has alarm feature too. The time is showing up properly and I am also setting multiple alarm properly.
I am creating multiple alarm using different id and also saving the same into Database so that I can view the list of alarms in a listview. Now I am trying to set ON and OFF functionality for my alarm. I have a problem there.
On itemclick if alarm is ON it switches OFF with the help of:
Intent intent = new Intent(Main.this,TaskRecieverForAlarm.class);
PendingIntent pi = PendingIntent.getBroadcast(Main.this, Integer.parseInt(cont[0]), intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pi);
The above code cancels the alarms perfectly fine.
To switch ON the alarm I am using:
Intent intent = new Intent(Main.this, TaskRecieverForAlarm.class);
intent.putExtra("AlarmDate", cont[1]);
intent.putExtra("key", Integer.parseInt(cont[0]));
PendingIntent sender = PendingIntent.getBroadcast(Main.this, Integer.parseInt(cont[0]) , intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
if(type.equalsIgnoreCase("daily"))
{
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1440*60000 ,sender);
}
else if(type.equalsIgnoreCase("weekly"))
{
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender); am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 7*1440*60000 ,sender);
}
Now as soon as I click the OFF to ON, alarm triggers and calls the TASKReceiverFORAlarm (broadcast receiver) even though the alarm time is 4 or 5 hours from the current time. I am not sure where I am going wrong?
Can somebody help me out?
Thanks!
I think I found the answer here:
public void setRepeating (int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
Added in API level 1
Schedule a repeating alarm. Note: for timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler. If there is already an alarm scheduled for the same IntentSender, it will first be canceled.
Like set(int, long, PendingIntent), except you can also supply a rate at which the alarm will repeat. This alarm continues repeating until explicitly removed with cancel(PendingIntent). If the time occurs in the past, the alarm will be triggered immediately, with an alarm count depending on how far in the past the trigger time is relative to the repeat interval.
If an alarm is delayed (by system sleep, for example, for non _WAKEUP alarm types), a skipped repeat will be delivered as soon as possible. After that, future alarms will be delivered according to the original schedule; they do not drift over time. For example, if you have set a recurring alarm for the top of every hour but the phone was asleep from 7:45 until 8:45, an alarm will be sent as soon as the phone awakens, then the next alarm will be sent at 9:00.
If your application wants to allow the delivery times to drift in order to guarantee that at least a certain time interval always elapses between alarms, then the approach to take is to use one-time alarms, scheduling the next one yourself when handling each alarm delivery.
Parameters
type One of ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP}, RTC or RTC_WAKEUP.
triggerAtMillis time in milliseconds that the alarm should first go off, using the appropriate clock (depending on the alarm type).
intervalMillis interval in milliseconds between subsequent repeats of the alarm.
operation Action to perform when the alarm goes off; typically comes from IntentSender.getBroadcast().
The way you use that function is:
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1440*60000 ,sender);
Try this one:
//The only variable here is the desired hour of the alarm, which
// has to be obtained in milliseconds
long alarmSetAt = // The hour of the Alarm for the current date in milliseconds
long time = cal.getTimeInMillis() - alarmSetAt;
if(time > 0){
time = -time + cal.getTimeInMillis();
}
else{
time = time + cal.getTimeInMillis() + 1440*60000;
}
am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 1440*60000 ,sender);
I am starting my service using below code repeatedly. My service starts at 8am everyday. And AlarmManager repeates at every 1 min. I want to stop this sevice at 6pm. how can I do this ?
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent loggerIntent = PendingIntent.getBroadcast(this, 0,new Intent(this,AlarmReceiver.class), 0);
Calendar timeOff9 = Calendar.getInstance();
timeOff9.set(Calendar.HOUR_OF_DAY, 08);
timeOff9.set(Calendar.MINUTE, 00);
timeOff9.set(Calendar.SECOND, 00);
//--------------------------------------------------------------------------------------------------------------------
long duration = userinterval * 60 * 1000;
manager.setRepeating(AlarmManager.RTC_WAKEUP,timeOff9.getTimeInMillis(), duration, loggerIntent);
In order to cancel at 6pm exactly, I would consider 2 options:
Each time the alarm triggers (i.e. every 1 minute), check the time, and cancel if time is after 6PM.
Set a once-off alarm in AlarmManager to go off at 6PM exactly. In that alarm, cancel.
I prefer option 2 for simplicity, and modularity of each code block. So for me, I would use (2) in my proof-of-concept code, while working on the solution.
But option 1 is better from a resources point of view, as the Android system only needs to remember a single alarm. I would use (1) in my final production code.
This way of working is just my personal preference, and most ppl probably will say to use (1) right away from the start.
The details about cancelling are below...
As for how to cancel an alarm, you don't often beat an answer by #commonsware....
Below answer copied from How to cancel this repeating alarm?
Call cancel() on AlarmManager with an equivalent PendingIntent to the one you used with setRepeating():
Intent intent = new Intent(this, AlarmReceive.class);
PendingIntent sender = PendingIntent.getBroadcast(this,
0, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.cancel(sender);
I'm building a reminders application where one time, weekly, monthly reminders and we notify the user of the reminder on due date and time. Reminders can be updated any time by the user to update the reminding time or delete the reminder altogether. I have thought of two ways I can solve the particular problem.
Whenever user sets a reminder, schedule an alarm accordingly with an unique Id and update or delete it in case user updates or deletes the alarm.
Since I store the reminding time in DB, better approach would be to schedule an alarm for the nearest reminder. And have the Service which is triggered by the alarm schedule a new alarm for the next nearest reminder.
2nd approach seems clean approach but how do we tackle the case where the Service triggered by alarm gets killed by the system before it schedules a new alarm for the next reminder?
Edit
Looks like if the system kills a Service for memory, it will re-create the Service. Does it mean it is safe to rely on the Service to schedule alarm every time it is run?
Edit 2
I've realized that Android kills any alarms whenever the device is restarted. This makes approach 2 a better solution. I've implemented it for now.
The pending intent needs to be created exactly in the same way for canceling the already set alarm. You can cancel previous alarm when you set a new alarm, if you want to have a single alarm activated at some time.
For setting alarm use:
Intent myIntent = new Intent(getApplicationContext(), SessionReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, now.getTimeInMillis(), pendingIntent);
For canceling the alarm use:
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent myIntent = new Intent(getApplicationContext(), SessionReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.cancel(pendingIntent);