Android repeating alarm not repeating correctly

5.7k views Asked by At

I have an alarm that I am wanting to repeat around every 5 minutes. For testing purposes, I have it set to repeat once every 5 seconds instead, as such:

AlarmManager alarmManager = (AlarmManager)getActivity().getSystemService(getActivity().ALARM_SERVICE);
        Intent intent = new Intent(getActivity(), CoordinateAlarmReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getService(getActivity(), 1, intent, 0);
        int repeatSeconds = 5;
        alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
                repeatSeconds * 1000, pendingIntent);

And the receiving IntentService prints a log statement when it receives the alarm. However, it fires around once every minute and a half instead of once every 5 seconds, where is it set incorrectly? I have also tried using setRepeating() instead of setInexactRepeating() but I get the same results.

Here is my alarm receiver:

public class CoordinateAlarmReceiver extends IntentService {

    public CoordinateAlarmReceiver(){
        super("CoordinateAlarmReceiver");
    }

    /*
    Alarm received, get new contacts which then shows notification
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        MyLog.i("coordinate alarm received");

        //new GetNewContactsTask(this).execute();
    }
}
2

There are 2 answers

0
Robin Dijkhof On

I assume you are on api 19 or above. The alarmmanager documentations says:

Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

You tried using setRepeating() but on api 19 and above this calls setInexactRepeating(). On 19 and above you

setInexactRepeating(): Schedule a repeating alarm that has inexact trigger time requirements; for example, an alarm that repeats every hour, but not necessarily at the top of every hour.

This explains your weird result.

If you want to set is at a excat time, you should use setExact. Unfortunalety there is no setExactRepating so you have to create this yourself. Schedule a new alarm after one executes or something like that.

Note in the alarmmanager documentation:

Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.

Maybe you should take a look at this.

0
Matt On

I had a similar problem in which I needed a Service fired every 15 seconds... I did the following.

  1. I have a class that extends Application called MyApplication. This class holds an instance of an alarm manager.

    public class MyApplication extends Application {
        private MyAlarmManager alarmMgr;
    
        @Override
        public void onCreate() {
            Log.d(TAG, "MyApplication onCreate");
            super.onCreate();
            Log.d(TAG, "initing alarmMgr ...");
            alarmMgr = new MyAlarmManager(this);
        }
    
        public MyAlarmManager getAlarmManager(){
            return alarmMgr;
        }
    }
    
    1. An AlarmManager called MyAlarmManager creates, starts & stops the alarms AND NOW sets the next alarm for this one service.

      public class MyAlarmManager {
          private MyApplication mApp;
          private Intent intent;
          private PendingIntent pendingIntent;
          private AlarmManager alarmMgr;
          private static final long FREQUENCY = 15000;
      
          public MyAlarmManager(Context context) {
              mApp = (MyApplication) context;
              // Android alarm service
              alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
      
              // service to be fired every 15 seconds
              intent = new Intent(context, MyService.class);
              pendingIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
              setNextAlarm();
          }
      
          public void setNextAlarm(){
              Log.d(TAG, "setting next alarm...");
              alarmMgr.set(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + FREQUENCY), pendingIntent);
          } 
      
          private void stopAlarms(){
              Log.d(TAG, "stopping Alarms");
              alarmMgr.cancel(pendingIntent);
          }
      
      }
      
    2. When the Service is fired I get an instance of MyApplication, get the AlarmManager and schedule the next alarm.

      public class MyService extends Service {
          MyApplication mApp;
      
          @Override
          public int onStartCommand(Intent intent, int flags, int startId) {
              Log.d(TAG, "in onStartCommand");
              // init the app reference if needed
              if (mApp == null) {
                  Log.d(TAG, "app was null. Creating now...");
                  mApp = (MyApplication) getApplicationContext();
              }
      
              // schedule the next zone check
              mApp.getAlarmMgr().setNextAlarm();
      
             // custom functionality ... 
         }