6

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.

Wezelkrozum
  • 831
  • 5
  • 15

4 Answers4

1

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?

FabianCook
  • 20,269
  • 16
  • 67
  • 115
  • 1
    Looking in the documentation, SystemClock.elapsedRealtime() is the time since the phone booted, not the actual time. Furthermore, I don't think the setTimeInMillis(0) call is necessary, because you want the alarm 1 day from now, not 1 day from epoch (which is ages ago). – Alex Curran Jun 02 '12 at 21:54
  • 1
    But I believe he is using the 1 day as an interval not an actual time? – FabianCook Jun 02 '12 at 21:59
  • 1
    yeah, but I'm assuming this problem is with the trigger time which is set using the `Calendar`. The 1-day interval is defined using the `Integer` and should be fine. – Alex Curran Jun 02 '12 at 22:22
  • 2
    Since I reschedule the PendingIntent after the phone is booted it won't be a problem to use SystemClock.elapsedRealtime(). It would be nicer to make it independent from the phones idle and active time, but I don't think it will hurt anything. I'm going to log the triggers and report back tomorrow. – Wezelkrozum Jun 02 '12 at 22:56
  • 1
    `elapsedRealtime()` is counted in milliseconds since the system was booted, including deep sleep. – Andrey Ermakov Jun 02 '12 at 23:29
1

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.

Sam
  • 86,580
  • 20
  • 181
  • 179
  • 1
    Thanks for your effort but I've done this already. When I analyse this data it should trigger the PendingIntent right on time, but it doesn't. So, that's the problem. – Wezelkrozum Jun 02 '12 at 23:30
  • 1
    Sorry to hear that... Tag me when you post new data, I'll help if I can. – Sam Jun 02 '12 at 23:38
  • 1
    @Wezelkrozum I added a possible answer. – Sam Jun 03 '12 at 19:51
1

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

}
Rescue9
  • 338
  • 2
  • 7
  • 1
    To be honest I'm that is not the fix. I'm create the Calendar within the method. But I do see a difference in the way we retrieve our PendingIntent. You use the getBroadcast method, while I'm using the getService method. – Wezelkrozum Apr 22 '13 at 00:27
1

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;
    }
}
Håvard
  • 767
  • 1
  • 4
  • 7