Android Alarm Manager Set Repeating at Specific Timing

时光总嘲笑我的痴心妄想 提交于 2019-12-07 03:29:29
forcewill

The problem is in calendar.getTimeInMillis() in

mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
            calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi);

The second argument to setInexactRepeating quoting the doc

triggerAtMillis time in milliseconds that the alarm should first go off, using the appropriate clock (depending on the alarm type). This is inexact: the alarm will not fire before this time, but there may be a delay of almost an entire alarm interval before the first invocation of the alarm.

Meaning it will run the first time aproximally one minute after you set it because of

calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 0 );
calendar.set(Calendar.MINUTE, 1);

If you wan't the first run of the alarm to be the next day do a calendar.add(Calendar. DATE, 1);`

As to the it stopped working, did you reboot de device ? AlarmCalendar alarms don't persist to device reboot, you can register a BroadcastReceiver to receive BOOT_COMPLETED event and register the alarm again check does Alarm Manager persist even after reboot?

Update: as you requested here is some help after reviewing your code

In your BOOT_COMPLETED Receiver class:

public void onReceive(Context context, Intent i) {
    if (i.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
        ReminderAlarm.scheduleAlarms(this);
    }
}

In your ReminderAlarm class

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recurring);

if(!alarmInitialized(this) { 
    scheduleAlarms(this); 
}

}

public static void scheduleAlarms(Context context) {

    Calendar calendar = Calendar.getInstance();

    if(hasRunnedToday(context)) {       //if the alarm has run this day
        calendar.add(Calendar.DATE, 1); //schedule it to run again starting tomorrow
    }

    long firstRunTime = calendar.getTimeInMillis();

    AlarmManager mgr = (AlarmManager) context
            .getSystemService(Context.ALARM_SERVICE);
    Intent notificationIntent = new Intent(context, ReminderAlarm.class);
    PendingIntent pi = PendingIntent.getActivity(context, 0,
            notificationIntent, 0);

    mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP,
            firstRunTime, AlarmManager.INTERVAL_DAY, pi);
}

public static boolean alarmInitialized(Context context) {
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);

    long alarmLastRun = preferences.getLong("AlarmLastRun", -1);


    return alarmLastRun != -1;

}

public static void updateAlarmLastRun(Context context) {
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);


    preferences.edit()
            .putLong("AlarmLastRun", new Date().getTime())
        .apply();
}

public static boolean hasRunnedToday(Context context) {
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE);

    long alarmLastRun = preferences.getLong("AlarmLastRun", -1);

    if(alarmLastRun == -1) {
        return false;
    }

    //check by comparing day, month and year
    Date now = new Date();
    Date lastRun = new Date(alarmLastRun);


    return now.getTime() - lastRun.getTime() < TimeUnit.DAYS.toMillis(1);
}

Each time your Reminder class alarm runs you should call updateAlarmLastRun to update the last time the alarm has run, this is necessary because the alarm may be schedule to be run on a day and the user reboots the device before the alarm has run in that case we don't want to use calendar.add(Calendar.DATE, 1); since that would skip a day.

On your Manifest.xml

<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
     <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
    </receiver>

Notes:

  1. You shouldn't do context = this if context is a class field since the object holds a reference to its field context and context field holds a reference to the object that would leak
  2. Your Receiver 'onReceive` doesn't has the extras you assumed to have like "notificationCount" onReceive by the system when your device finish boot.
  3. Once your alarm runs call updateAlarmLastRun

Hope any of this helps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!