I'm working on an app that involves an AlarmManager, and I can't seem to get it to fire. I was using a Handler originally, but I switched over to the AlarmManager so that I can wake the phone up from sleep.
Here's what I have so far:
int timeBetweeninMillis = 3 * 60000;
if (ManagerService.serviceRunning) {
Intent alarmIntent = new Intent(AlarmReceiver.ACTION_RECEIVE);
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 400, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, (SystemClock.elapsedRealtime() + timeBetweeninMillis), alarmPendingIntent);
}
The AlarmManager either won't fire or will fire extremely late (like 10 minutes after).
The app is written with API 16 and is being tested on a phone with API 19.
Thank you for your help!
There's an issue with new PendingIntents recycling existing PendingIntents that might cause issues with AlarmManager.
To workaround that, I always add a unique value to all my PendingIntents, this one-liner does the trick in most cases:
Intent alarmIntent = new Intent(AlarmReceiver.ACTION_RECEIVE);
alarmIntent.setData(Uri.parse("custom://" + System.currentTimeMillis())); // MAKE INTENT UNIQUE
PendingIntent alarmPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 400, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, (SystemClock.elapsedRealtime() + timeBetweeninMillis), alarmPendingIntent);
Also, I don't know what's ManagerService.serviceRunning in your code, but I would add some log to the else case to make sure you're actually running that code block.
EDIT:
try using mAlarmManager.setExactAndAllowWhileIdle instead of mAlarmManager.set this will force AlarmManager to call your code exactly when requested, and prevent device idle time from interfering with the alarm.
See:
https://developer.android.com/reference/android/app/AlarmManager.html#setExactAndAllowWhileIdle(int, long, android.app.PendingIntent)
Related
In my code the Interval ( third parameter) on setRepeating() method seems not firing every 5 sec .
It keeps increasing in time, it's like the first one or 2 are mostly in time but the others fires like after 40+secs
So what's wrong here?
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = new Intent(this, MainActivity2Activity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE );
am.setRepeating(RTC_WAKEUP,System.currentTimeMillis(),1000*5,pi);
}
}
Take a look here: http://developer.android.com/reference/android/app/AlarmManager.html#setRepeating(int, long, long, android.app.PendingIntent)
As you're firing alarm every 5 seconds:
Note: for timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Your code is ok. Explanation of a delay you're experiencing may be:
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.
From what I understand from your code you are trying to run MainActivity2Activity.class 5 seconds after the creation of MainActivity.class.
I would advice you to use FLAG_UPDATE_CURRENT instead of FLAG_CANCEL_CURRENT in your pending intent.
The FLAG_CANCEL_CURRENT would retain your first ever pending intent and won't update or create a new one until and unless you cancel the original pending intent first.
Using FLAG_UPDATE_CURRENT will ensure that the pending intent is updated every time MainActivity.class is executed, so that pending intent will be fired exactly after 5 seconds the MainActivity.class is created.
Hope this helps.
Basically you wrote PendingIntent.FLAG_CANCEL_CURRENT instead of PendingIntent.FLAG_ONE_SHOT.
Code for Set Alarm by Alarm Manager
AlarmManager alarmManager = (AlarmManager) getBaseContext().getSystemService(ALARM_SERVICE);
Intent i1 = new Intent(this, ReceiveAlarmActivity.class);
i1.putExtra("Key", "Value");
PendingIntent operation = PendingIntent.getActivity(getBaseContext(), 0, i1, PendingIntent.FLAG_ONE_SHOT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Your_Date.getTime(), 5000 operation);
You have to pass Your Date.
Done
This is my first post here. I have searched all around for this topic, but nothing seems to help. When the code below gets executed, the alarm still goes off, when it should not.. meaning that I cannot cancel the alarm, making my app useless for API's lower than 21. Any idea why? Please help! I should mention that when I try this code using an API22 emulator(nexus one) from Android Studio it works, but when I use it with an API18 emulator(samsung s3) from genymotion it does not.
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 8, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent);
am.cancel(pendingIntent);
Looks like you're just not giving set() enough time to set the alarm before you're calling cancel().
Put the call to cancel() in a separate code block so that it's not being called immediately after set(), and it should work.
I'm attempting to use AlarmManager to schedule a delayed check in my app. (Specifically, N minutes after a user approaches a location, I want to check whether they're still there, and if so send them a notification.)
I've implemented this by checking to see whether they've entered the region in my location update receiver and, if they have, scheduling like so:
Intent geofenceIntent = new Intent(context, GeofenceReceiver.class)
// ...intent contents not important...
PendingIntent pi = PendingIntent.getBroadcast(context, 0, geofenceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar c = Calendar.getInstance();
c.add(Calendar.SECOND, getGeofenceDelaySeconds());
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);
Log.v("Scheduling notification check for "+c.getTime());
When the battery level is high (say, 50%), everything works like a charm. But when it's low (say, 10%), I get location updates, they schedule the alarm seemingly-successfully, but that alarm never actually triggers!
What gives? Does Android stop sending certain types of updates when it's trying to conserve power? How can I work around this (short of actually keeping my app active for the duration of the delay, which causes obvious issues with battery life)?
It turns out that this is related to the use of the real-time clock.
Although I could not find the documentation it quotes (it's not in AlarmManager), this StackOverflow answer suggests that AlarmManager.RTC_WAKEUP alarms do not trigger if the phone is in power-saving mode. AlarmManager.ELAPSED_REALTIME_WAKEUP alarms do not seem to suffer this problem, so I was able to fix the issue by switching to:
Intent geofenceIntent = new Intent(context, GeofenceReceiver.class)
// ...intent contents not important...
PendingIntent pi = PendingIntent.getBroadcast(context, 0, geofenceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
long millis = SystemClock.elapsedRealtime() + 1000 * getGeofenceDelaySeconds();
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, millis, pi);
I'm looking for a solution for days now. There might not even be a solution.
What happens is the following:
I got an application which schedules alarms for users, for the user to get out of bed. It's really important that the alarms "always" go off.
To be able to let the alarms go off I make use of an AlarmManager. This schedules intents to be executed on scheduled times. This works fine when the Application is open or closed with the back/home button.
When I close the app with Force Close option, the Alarm Manager alarms get cleared from the system and they will not go off.
I have tried the following things already:
START_STICKY Service
DefaultUncaughtExceptionHandler - Won't work, because there isn't an exception caught for force closing the app.
Broadcast Receiver - The issue is with the alarms being deleted.
I'm wondering if anyone has experienced the same issue with the AlarmManager class and if you found a solution or alternative to fix this problem.
p.s. I'm creating the Alarm Manager alarms like this:
Intent myIntent = new Intent(getApplicationContext(), CheckAlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(),
1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)getApplicationContext().getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
int daysTillAlarm = AlarmHelper.calculateDaysTillAlarm(alarm);
calendar.add(Calendar.DATE, 0);
calendar.set(Calendar.HOUR_OF_DAY, 15);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
EDIT:
To try and see if I wasn't the only one with the issue, I downloaded some well used alarm clocks. They all seem to have the same behavior as I do. For now I'll leave it be. They're also well rated.
Still if you might have the solution to this problem I'd like to know!
Try changing you code:
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(),
1, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
to:
PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext(),
1, myIntent, 0);
Also try adding:
alarmManager.cancel(pendingIntent);
before:
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
From my point of view (as Android user) this is right behavior. Imagine application which has bug leading to crash (with crash dialog), and this application scheduled some action to be started every minute. What can you do with crash dialog appearing every minute?
So I hope there is no direct answer to your question (like "just call this method").
As always, there are ugly ways - like starting several processes which track all others and restart if needed, but then your application starts to look like virus...
I've searched for 3 days now but didn't find a solution or similar problem/question anywhere else. Here is the deal:
Trigger in 1 hour -> works correct
Trigger in 2 hours -> Goes of in 1:23
Trigger in 1 day -> Goes of in ~11:00
So why is the AlarmManager so unpredictable and always too soon? Or what am I doing wrong? And is there another way so that it could work correctly?
This is the way I register my PendingIntent in the AlarmManager (stripped down):
AlarmManager alarmManager = (AlarmManager)parent.getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(parent, UpdateKlasRoostersService.class);
PendingIntent pendingIntent = PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//Set startdate of PendingIntent so it triggers in 10 minutes
Calendar start = Calendar.getInstance();
start.setTimeInMillis(SystemClock.elapsedRealtime());
start.add(Calendar.MINUTE, 10);
//Set interval of PendingIntent so it triggers every day
Integer interval = 1*24*60*60*1000;
//Cancel any similar instances of this PendingIntent if already scheduled
alarmManager.cancel(pendingIntent);
//Schedule PendingIntent
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, start.getTimeInMillis(), interval, pendingIntent);
//Old way I used to schedule a PendingIntent, didn't seem to work either
//alarmManager.set(AlarmManager.RTC_WAKEUP, start.getTimeInMillis(), pendingIntent);
It would be awesome if anyone has a solution. Thanks for any help!
Update:
2 hours ago it worked to trigger it with an interval of 2 hours, but after that it triggered after 1:20 hours. It's getting really weird. I'll track the triggers down with a logfile and post it here tomorrow.
Update:
The PendingIntent is scheduled to run every 3 hours. From the log's second line it seems like an old scheduled PendingIntent is still running:
[2012-5-3 2:15:42 519] Updating Klasroosters
[2012-5-3 4:15:15 562] Updating Klasroosters
[2012-5-3 5:15:42 749] Updating Klasroosters
[2012-5-3 8:15:42 754] Updating Klasroosters
[2012-5-3 11:15:42 522] Updating Klasroosters
But, I'm sure I cancelled the scheduled PendingIntent's before I schedule a new one. And every PendingIntent isn't recreated in the same way, so it should be exactly the same. If not , this threads question isn't relevant anymore.
When using a calendar are you taking into account that the calendar uses the time right down to Milli seconds. Maybe you should set the Milli second field and the seconds field to zero so it's going of on the dot.
Also for a day it would be easier to use this
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.add(Calendar.DAY_OF_MONTH, 1);
Also when you use getInstance doesn't that set the calendars time to the time it was created so there shouldn't be any need to set the time again right?
Rewrite: I eventually saw your error, but unpredictably.
I did changed this:
PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
to this:
PendingIntent.getService(parent, 0, myIntent, PendingIntent.FLAG_CANCEL_CURRENT);
under the same assumption as you that somehow an old intent is broadcasting. I haven't seen the fluke since...
Also the only times I saw it were during my initial call. Another approach could be to track a current and a previous Calendar object, if the interval isn't what you expected then ignore this "early" broadcast. (While this method seems redundant considering how the alarm should work, it helps prevent those extraneous calls considering how the alarm is working...)
Hope that helps, I'll let you know if I find anything else.
I know this question is a bit old, but I had this same problem myself. I found out that if I tried to declare the Calendar variable outside of the method, it wouldn't play nicely and the alarms would fire early. Because your class is stripped down it is hard to tell exactly where you're calling the calendar instance.
If I set it up as such, then it would fire right on time:
protected void nextAlarm(Context context, int seconds){
Calendar nextAlarm = Calendar.getInstance();
Intent intent = new Intent(context, MyClass.class);
PendingIntent pending = PendingIntent.getBroadcast(context, MainActivity.REPEATING_ALARM, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager amanager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
nextAlarm.add(Calendar.SECOND, seconds);
amanager.set(AlarmManager.RTC_WAKEUP, nextAlarm.getTimeInMillis(), pending);
}
Make sure your service's onStartCommand returns START_NOT_STICKY, otherwise it will be automatically re-attempted:
public class UpdateKlasRoostersService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
buildUpdate();
return START_NOT_STICKY;
}
}