Search code examples
androidbroadcastreceiveralarmmanager

AlarmManager alarm goes off at the wrong time


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?


Solution

  • 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.