Search code examples
androidalarmmanager

Android's alarm manager wrong period


I am creating AlarmManager for my app in order to send sms messages in different periods. When I put a time for AlarmManager for example 5 minutes, it wakes up almost immediately about 1-2 times, but after this it works correct. After I change value of period the situatuion repeats. I think this is something wrong with stopping AlarmManager or with setting a repeater.

This is my makeAlarm function:

  private void makeAlarm() {
    cancelAlarm();

    Intent i = new Intent(this, SmsAlarmReceiver.class);

    PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), SmsAlarmReceiver.REQUEST_CODE,
            i, PendingIntent.FLAG_UPDATE_CURRENT);

    long firstMillis = System.currentTimeMillis();

    SharedPreferences refreshSettings = getSharedPreferences("com.example.xd720p.sensorcontroller_09082016",
            Context.MODE_PRIVATE);

    double refreshForTValue = Double.valueOf(refreshSettings.getString("tempPeriod", "30"));

    if (refreshForTValue <= 0 ) {
        cancelAlarm();
    } else {
        long period = Math.round(refreshForTValue * 60 * 1000);
        AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
        alarm.setRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
                firstMillis + period, pendingIntent);
    }
}

This is my cancelAlarm function:

  private void cancelAlarm() {
    try {
        Intent i = new Intent(this, SmsAlarmReceiver.class);
        PendingIntent pIntent = PendingIntent.getBroadcast(this.getApplicationContext(), SmsAlarmReceiver.REQUEST_CODE,
                i, 0);

        AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);

        alarm.cancel(pIntent);
        pIntent.cancel();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

This is my SmsAlarmReceiver class which extends BroadcastReceiver:

  public class SmsAlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 322;


  @Override
  public void onReceive(Context context, Intent intent) {

      Intent i = new Intent(context, SmsSenderService.class);
      context.startService(i);
  }
}

I create my alarm in onCreate method in MainActivity. Also I stop my alarm and making new, when I change period value. This value stores in SharedPreferences, so I tried to recreate alarm in onSharedPreferenceChanged, but it makes no sense in my situiation.


Solution

  • Finally, i solved it out! Here is my solution in makeAlarm() function:

        private void makeAlarm() {
        cancelAlarm();
    
        Intent i = new Intent(this, SmsAlarmReceiver.class);
    
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), SmsAlarmReceiver.REQUEST_CODE,
                i, PendingIntent.FLAG_CANCEL_CURRENT);
    
        SharedPreferences refreshSettings = getSharedPreferences("com.example.xd720p.sensorcontroller_09082016",
                Context.MODE_PRIVATE);
    
        double refreshForTValue = 0;
    
    
        refreshForTValue = Double.valueOf(refreshSettings.getString("tempPeriod", "30"));
    
    
        if (refreshForTValue <= 0 ) {
            cancelAlarm();
        } else {
            long period = Math.round(refreshForTValue * 60 * 1000);
            AlarmManager alarm = (AlarmManager) getSystemService(ALARM_SERVICE);
            long firstMillis = System.currentTimeMillis();
            alarm.setRepeating(AlarmManager.RTC_WAKEUP, firstMillis + period,
                    period, pendingIntent);
        }
    }
    
    1. As you can see I changed setRepeating() arguments. The thing is that second argument not only for set start time of the period, but it wakes alarm up in the start time. So we need to add period value if we don't want to wake up alarm immediately. And the third argument is just a repetition period, so we need to remove start time. You can read about this in examples here: https://developer.android.com/training/scheduling/alarms.html

    2. In PendingIntent.getBroadcast() we need to change flag from FLAG_UPDATE_CURRENT to FLAG_CANCEL_CURRENT. I can't exactly explain why, but according to the documentation when we set UPDATE flag some of the changed properties will be ignored. Therefore alarm firstly will wake up in an old period. But CANCEL_FLAG allows us to replace properties and wake alarm up with new period. I'm sorry if my explanation is incorrect: as I said I didn't fully understand this moment. I will be glad if someone give good explanation.