Search code examples
androidandroid-alarms

Android AlarmManager not working when set for longer time


In my app I have tried to set an alarm using this code:

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, 2016);
        calendar.set(Calendar.MONTH, 1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 15);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 1);
        calendar.set(Calendar.MILLISECOND, 1);

        Intent intent = new Intent(G.context, AlarmService.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent pendingIntent = PendingIntent.getService(getApplicationContext, 1010, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        G.alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);

It works when I set the alarm for 1 minute or later, but not when I set the alarm for 30 or 40 minutes later. While I am not on the phone for 30 minutes, after 30 minutes the alarm did not work, and when the phone screen is on the alarm worked...

Any help would be appreciated.


Solution

  • Since API 19 set() is treated as inexact and may be delayed. If you really need a precise alarm, you should use setExact() (available since API 19) instead :

    Note: Beginning in API 19, the trigger time passed to this method is treated as inexact: the alarm will not be delivered before this time, but may be deferred and delivered some time later. The OS will use this policy in order to "batch" alarms together across the entire system, minimizing the number of times the device needs to "wake up" and minimizing battery use. In general, alarms scheduled in the near future will not be deferred as long as alarms scheduled far in the future.

    This change happen on 19+ device (obviously) but also only if the APK's target API is 19+, so you can

    Additionnaly when you use a *_WAKE_UP alarm, the alarm manager garantees that the device will be awake long enough to execute the receiver's method, but not the service it may launch :

    The Alarm Manager holds a CPU wake lock as long as the alarm receiver's onReceive() method is executing. This guarantees that the phone will not sleep until you have finished handling the broadcast. Once onReceive() returns, the Alarm Manager releases this wake lock. This means that the phone will in some cases sleep as soon as your onReceive() method completes. If your alarm receiver called Context.startService(), it is possible that the phone will sleep before the requested service is launched.

    The support v4 library provides a usefull helper class to handle this case : WakefulBroadcastReceiver

    In you case, as you are using a service pending intent, I am not sure what wake garanties apply.