Broadcast receiver fires late than it should be - android

I am trying to fire a receiver at specific time of day which is 12 Am, but sometimes it fires at 1 or 2 AM.
I added a notifcation to my service to know when exactly the receiver start accourding to the alarm, and I find out, it start at 1, or 2 even 3 Am, not as I adjusted.
calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY,0);
calendar.set(Calendar.MINUTE,0);
calendar.set(Calendar.SECOND,0);
Intent intent = new Intent(getActivity(), PrefAlarm.class);
long firstMillis = System.currentTimeMillis();
alarm = (AlarmManager) getActivity().getSystemService(getActivity().ALARM_SERVICE);
pIntent = PendingIntent.getBroadcast(getActivity(), PrefAlarm.REQUEST_CODE2,intent ,PendingIntent.FLAG_CANCEL_CURRENT);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis( ),AlarmManager.INTERVAL_DAY,pIntent);

If you use setInexactRepeating(), the time that it triggers is inexact. This means that Android can adjust the trigger time to save battery (usually by delaying the trigger until the device is awake). Read the documentation about AlarmManager and JobScheduler and about how to get thedesired behaviour for your application.

Related

How to set android alarm to trigger until an specific date

I'm new to android and using alarmManager and I was wondering if there is a way to set an alarm in android that triggers for example every monday until a certain specific date. Like this :
Start date 10/09/15
Remind me something every monday at 2:30 pm
Until
End date 11/09/15
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 14);
calendar.set(Calendar.MINUTE, 30);
int weekInMillis = 7 * 24 * 60 * 60 * 1000;
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
weekInMillis, PendingIntent.getBroadcast(context, 0, new Intent(context, ReminderAlarmWakefulBroadcastReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT));
Above code snippet sets an alarm for 2:30 PM that repeats itself every week. Tweak calendar for varying the time at which the alarm goes off. For example, the coming Monday.
When the alarm goes off, it sends a broadcast which will be received by ReminderWakefulBroadcastReceiver, a custom receiver containing the code that you want to run every Monday at 2:30 PM. This code should also check whether it is time to cancel the alarm and if it is, the following code cancels it:
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(PendingIntent.getBroadcast(context, 0, new Intent(context, ReminderAlarmWakefulBroadcastReceiver.class));
References:
AlarmManager, Scheduling Repeating Alarms, PendingIntent
If you know how to setup an Alarm, the solution is quite simple:
1) At the time you setup the Alarm, calculate the maximum timestamp you want it to run, and save it as a local preference.
2) Then in the Alarm code itself, each time it is triggered you can make a first test to see if the current timestamp is before or after your limit preference saved at first time.
3) If reached, then cancel the Alarm as #karthik said. If not, keep your code going...

Android daily repeating notification at specific time of a day using AlarmManager

I need to the Android app to send notification to remind users at 8am, 3pm and 8pm every day. So I use the following three lines in onCreate() of the MainActivity, when the application starts. However, when I run the app, all three notification are coming at once instead of at the wanted time.
setRepeatedNotification(1,8,0,0);
setRepeatedNotification(2,15,0,0);
setRepeatedNotification(3,20,0,0);
Why is that? I also attach the setRepeatedNotification function here. Thank you!
private void setRepeatedNotification(int ID, int hh, int mm, int ss) {
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent alarmIntent = new Intent(MainActivity.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, ID, alarmIntent, 0);
Calendar calendar = Calendar.getInstance();
// calendar.set();
calendar.set(Calendar.HOUR_OF_DAY, hh);
calendar.set(Calendar.MINUTE, mm);
calendar.set(Calendar.SECOND, ss);
// Clear previous everyday pending intent if exists.
if (null != mEverydayPendingIntent) {
alarmManager.cancel(mEverydayPendingIntent);
}
mEverydayPendingIntent = pendingIntent;
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, mEverydayPendingIntent);
}
Here is the updated code:
private void setRepeatedNotification(int ID, int hh, int mm, int ss) {
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent alarmIntent = new Intent(StartActivity.this, AlarmReceiver.class);
alarmIntent.putExtra("ID",ID);
Log.d("setRepeatedNotification", "ID:" + ID);
PendingIntent pendingIntent = PendingIntent.getBroadcast(StartActivity.this, ID, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
Calendar now = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, hh);
calendar.set(Calendar.MINUTE, mm);
calendar.set(Calendar.SECOND, ss);
//check whether the time is earlier than current time. If so, set it to tomorrow. Otherwise, all alarms for earlier time will fire
if(calendar.before(now)){
calendar.add(Calendar.DATE, 1);
}
mEverydayPendingIntent = pendingIntent;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, mEverydayPendingIntent);
}
I see two potential problems with your setup with AlarmManager. The first arises when the device goes to sleep.
From AlarmManager's documentation:
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.
As you can see, if you've set an alarm and the device has gone to sleep, without using AlarmManager.RTC_WAKEUP there could be a long delay depending on how long the device has been in sleep for. If you've never touched your device and no other alarms caused a wakeup, it could cause all your alarms to stack up upon the next hour that the device is awake for.
Another potential issue I see is that you are retrieving a Calendar instance representing the time right now, but then setting the hour, minute and second by yourself. The current day and the current year have been automatically populated from the current time.
Again, from the documentation (emphasis mine):
If the stated trigger time is 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.
In this case, if your method was invoked past 8 pm on the given day, calendar.getTimeInMillis() will return a timestamp in the past for all three alarms, causing them to be triggered immediately since 8 am, 3 pm and 8 pm have already past in that day. In this case, you must first evaluate whether the current time is past the alarm interval you are trying to set and add 1 day more onto the time you are setting to make sure the alarm has been set in the future.

Calendar instance in android for AlarmManager

I am developing an app which displays notifications by using AlarmManager.
For that I'm taking the user input values for hour, minute and second.
Something like:
int hour = 4;
int min = 40;
int sec =36
Calendar Calendar_Object = Calendar.getInstance();
Calendar_Object.set(Calendar.HOUR, hour);
Calendar_Object.set(Calendar.MINUTE, min);
Calendar_Object.set(Calendar.SECOND, sec);
Intent myIntent = new Intent(MyView.this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(MyView.this,0, myIntent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC, Calendar_Object.getTimeInMillis(), myIntent);
Notifications and the rest of the code work fine, but the problem is that instead of 4:40:36 the notifications get invoked on the current time(as soon as i run/debug the app).
I think there is some problem in Calender_Object part.
Looking for a solution.
Thanks in advance.
Please note: Alarms will be executed immediately, if the notification time has elapsed already.
As a workaround you might want to consider a date part too. Or just a variable in memory which acts as a boolean if the time has elapsed or not.
From the Docs:
If the stated trigger time is in the past, the alarm will be triggered immediately. If there is already an alarm for this Intent scheduled (with the equality of two intents being defined by filterEquals(Intent)), then it will be removed and replaced by this one.
Also please consider the API level 19 version of how AlarmManager works.

Stop a service at specific time

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);

Starting alarm service in android

In my application i want to use alarm service for specific period of time.I'm taking start time and end time values from user and saving it in database,Now i want to start a alarm service at start time and alarm should go off at end time specified by user.I'm new to this topic and not able to understand how to implement this...Any help will be appreciated.Thank u..
This is how you implement an alarm manager. But you will need to read about Calendar object in android also.
String alarm = Context.ALARM_SERVICE;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 8);//Just an example setting the alarm for the 8th hour of a day.
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND,0);
calendar.set(Calendar.MILLISECOND, 0);
AlarmManager am = (AlarmManager)getActivity().getSystemService(alarm);
//This is the intent that is launched when the alarm goes off.
Intent intent = new Intent("WAKE_UP");
PendingIntent sender = PendingIntent.getBroadcast(getActivity(), 0, intent, 0);
//If the user wants the alarm to repeat then use AlarmManager.setRepeating if they just want it one time use AlarmManager.set().
am.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis() , AlarmManager.INTERVAL_DAY, sender);
}
Also you will need to register a BroadCast Receiver to except the intent when the alarm sets it off.
You create the BroadCast reciever and register it in your manifest to receive the intent from the alarm.
http://www.vogella.de/articles/AndroidServices/article.html
Here is a great tutorial to help you understand better
The key is to use the AlarmManager with a pending intent.
mAlarmSender = PendingIntent.getService(AlarmService.this,
0, new Intent(AlarmService.this, AlarmService_Service.class), 0);
Then you create the AlarmManager from the current context:
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
And schedule the previously created pending intent.
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
firstTime, 30*1000, mAlarmSender);
On schedule the AlarmService_Service service will be called, or you can put another intent like open a specific activity.
Here is the complete example of how you can schedule an alarm: AlarmService.java

Categories

Resources