【问题标题】:Alarms not cancelled未取消的警报
【发布时间】:2016-06-09 12:29:05
【问题描述】:

我正在使用以下代码取消所有警报并重置它们:

    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 &gt; 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);
    }

【问题讨论】:

  • 除了 user8 的回答之外,最好的方法是将 alarmManager 和 'PendingIntent' 设为全局并将它们用于启动和取消。如果您开发 target >=Marshmallow,请确保您已阅读此内容:developer.android.com/training/monitoring-device-state/…
  • 您将_id 设置为 System.timeInMillis() 的目标是什么?...这很不寻常....
  • 关于 Doze 的非常有趣的读物,谢谢!我正在使用系统millis,因为我在很多文章/警报示例代码中看到了这一点。您会建议改用什么?
  • 是哪些教程制作的?我猜这会把你引向错误的方向,或者这些 tuts 有其他目标。设置唯一Id 的简单步骤是例如来自arrayList itemcount。您只需将方法 setAlarm 调整为 setAlarm(Context context, Intent receiverIntent, String type, long timeMillis, int id) 并使用 setAlarm(mContext, receiverIntent, mArrayList.get(i).getType(), mArrayList.get(i).getDateMillis(),i); 将其传递到循环中
  • 好的,将您的 PendingIntent 更改为 FLAG_UPDATE_CURRENT(在 set 和 cancel() 方法上)并确保使用相同的上下文。还要确保 id 是正确的,因为我不知道代码,这对我来说似乎有点混乱。如果您确定一切设置正确,它应该可以工作。

标签: android android-pendingintent android-alarms


【解决方案1】:

除了 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);

为什么

好吧,为什么FLAG_CANCEL_CURRENT 不起作用,尚不清楚/记录在案,但我经常在 SO 中阅读此内容。文档告诉我们,这会取消现有的PendingIntent 并创建一个新的,如果您想在intent 中更改一些extra data,可以使用它。

FLAG_UPDATE_CURRENT 描述如下:

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

从这两个描述中,如果您使用 FLAG_CANCEL_CURRENT,我看不出它不应该与 alarmManager.cancel() 一起使用的原因。也许是因为 PendingIntent 被取消并在 alarmManager.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);
}

【讨论】:

  • 非常感谢您的回答,尤其是添加棉花糖!设置警报时,我正在向我的 Intent 添加额外内容,并且它似乎仍然有效。比较 Intent 时是否有可能忽略额外内容?
【解决方案2】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多