警报未取消

Alarms not cancelled

我正在使用以下代码取消并重置所有闹钟:

    for (int i = 0; i < mArrayList.size(); i++) {
  Intent receiverIntent = new Intent(mContext, AlarmReceiver.class);
        int _id = (int) mArrayList.get(i).getDateMillis(); //(int) System.currentTimeMillis();
        PendingIntent sender = PendingIntent.getBroadcast(mContext, _id, receiverIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(mContext.ALARM_SERVICE);
        alarmManager.cancel(sender);
        setAlarm(mContext, receiverIntent, mArrayList.get(i).getType(), _id, sender, alarmManager);
           }

    public static void setAlarm(Context context, Intent receiverIntent, String typ, long timeMillis, PendingIntent pendingIntent, AlarmManager 
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timeMillis);
        long sdl = calendar.getTimeInMillis();

        String notificationTitle = "My Title";
        String notificationText = "My Text";
        receiverIntent.putExtra("notificationTitle", notificationTitle);
        receiverIntent.putExtra("notificationText", notificationText);
        receiverIntent.putExtra("notificationDateTime", sdl);

        alarmManager.set(AlarmManager.RTC_WAKEUP, sdl, pendingIntent);
    }

问题是,当我第一次调用 CancelAllAlarms() 然后设置我的闹钟时,新的闹钟创建得很好,但旧的没有被删除。 因此,如果我第一次执行 adb shell dumpsys alarm > D:\test.txt,我有大约 200 个条目,下一个应用程序是 运行 我有大约 400 个,然后是 600 个等等...

编辑

我更改了我的代码很多,因为我现在将生成的 ID 存储在一个工作正常的数据库中。所以我的代码发生了重大变化:

Intent receiverIntent = new Intent(mContext, AlarmReceiver.class); AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(mContext.ALARM_SERVICE);

    String[] alarms = getAllAlarmsFromDB(databaseHAlarms, databaseHAlarms.tableName_alarms);
    for (int i = 0; i < alarms.length; i++) {
        //alarms[i] now holds the ID set before (see codee below)
        PendingIntent sender = PendingIntent.getBroadcast(mContext, Integer.parseInt(alarms[i]), receiverIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        alarmManager.cancel(sender);
    }

    for (int i = 0; i < mArrayList.size(); i++) {
        long timeMillis = mArrayList.get(i).getDateMillis();
        int _id = Integer.parseInt(String.valueOf(mArrayList.get(i).getDateMillis()).substring(0, 8));
        PendingIntent sender = PendingIntent.getBroadcast(mContext, _id, receiverIntent, PendingIntent.FLAG_CANCEL_CURRENT);

        insertAlarmIntoMySQL(databaseHAlarms, getMD5(timeMillis + ""), String.valueOf(mArrayList.get(i).getDateMillis()).substring(0, 8));

        alarmManager.set(AlarmManager.RTC_WAKEUP, sdl, sender);
    }

您需要将传递给 alarmManager.set()PendingIntent 传递给 alarmManager.cancel()

在您的代码中 _id 会有所不同,因此 PendingIntent 不相等,因此取消将不起作用。

ID 应该是唯一的(除非你总是想取消所有这些),但是当你想取消一个特定的警报时,你需要知道你在创建时用于 PendingIntent 的 ID它,并使用完全相同的 ID 取消它。

我建议将 ID 存储在 SQLite 数据库中。

除了 user13 的回答外,您还必须在 PendingIntent 上使用 FLAG_UPDATE_CURRENT

所以总而言之,一定要使用相同的Contextid并使用FLAG_UPDATE_CURRENT:

启动闹钟:

PendingIntent sender = PendingIntent.getBroadcast(mContext, id, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, time, sender);

停止闹钟:

PendingIntent sender = PendingIntent.getBroadcast(mContext, id, receiverIntent, PendingIntent.FLAG_CUPDATE_CURRENT);
alarmManager.cancel(sender);

为什么

嗯,clear/documented 为什么 FLAG_CANCEL_CURRENT 不起作用,但我经常在 SO 中阅读此内容。文档告诉我们,这会取消现有的 PendingIntent 并创建一个新的,如果您想更改 intent.

中的某些 extra data,您可以使用它

FLAG_UPDATE_CURRENT 描述如下:

如果您正在创建只有 extras 发生变化的意图,并且不关心任何收到您之前的 PendingIntent 的实体将能够使用您的新 extras 启动它,即使他们没有明确地给它。

从这两个描述中,我看不出如果您使用 FLAG_CANCEL_CURRENT 它不应该与 alarmManager.cancel() 一起工作的原因。也许是因为 PendingIntentalarmManager.cancel() 能够之前通过 FLAG 被取消并重新创建。

棉花糖

棉花糖有一些新情况。取消应该像以前一样工作,没有变化。但是如果设备进入休眠模式,使用 alarmManager.set() 设置闹钟将不起作用。描述您必须使用 setAndAllowWhileIdle()setExactAndAllowWhileIdle()setAlarmClock() 的文档。

但仅当您的应用程序需要在打瞌睡时触发警报时才这样做!因此,要为 Marshmallow 准备您的应用程序,您应该检查 API 版本并设置它所依赖的方法。

if (Build.VERSION.SDK_INT >= 23) {   

  PendingIntent sender = PendingIntent.getBroadcast(mContext, id, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
   alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, sender);


} else {        

    PendingIntent sender = PendingIntent.getBroadcast(mContext, id, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager.set(AlarmManager.RTC_WAKEUP, time, sender);
}