如何在时钟应用程序中正确取消由 AlarmManager 设置的 AlarmClock 闹钟?

How to correctly cancel an AlarmClock alarm set by AlarmManager in the Clock app?

这个问题已经有了答案here, here and 。但是他们没有被 OP 确认正在工作,在我的例子中,由同一个 PendingIntent 设置的警报不会被取消。 有没有办法取消闹钟闹钟?

@Override
protected void onHandleIntent(@Nullable Intent i) {
    Intent i = new Intent(AlarmClock.ACTION_SET_ALARM);
    i.putExtra(AlarmClock.EXTRA_SKIP_UI, true);
    i.putExtra(AlarmClock.EXTRA_HOUR, 6);
    i.putExtra(AlarmClock.EXTRA_MINUTES, 0);
    i.putExtra(AlarmClock.EXTRA_MESSAGE, "Good Morning");
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    AlarmManager alarmMgr = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
    PendingIntent alarmIntent = PendingIntent.getActivity(
                    this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
    alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime(),
                alarmIntent);
    Log.d(TAG, "Alarm set");

    try {
        Thread.sleep(15000);
        alarmMgr.cancel(alarmIntent);
        Log.i(TAG, "Alarm canceled");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

此代码按预期输出:

Alarm set
Alarm canceled

但是并没有取消设置的闹钟。我做错了什么?

我遇到了同样的问题,我阅读了你在问题中提到的那些话题。是的,它们不起作用。这就是我设法让它工作的方式:

设置闹钟:

 public static void setAlarm(Context context, int requestCode, int hour, int minute){


    AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context//same context should be used when canceling the alarm
            , AlarmReceiver.class);
    intent.setAction("android.intent.action.NOTIFY");

    //setting FLAG_CANCEL_CURRENT makes some problems. and doest allow the cancelAlarm to work properly
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);

    Calendar time = getTime(hour, minute);

    //set Alarm for different API levels
    if (Build.VERSION.SDK_INT >= 23){
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }
    else{
        alarmManager.set(AlarmManager.RTC_WAKEUP,time.getTimeInMillis(),pendingIntent);
    }

取消闹钟:

 public static void cancelAlarm(Context context, int requestCode){


    AlarmManager alarmManager =( AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

    //define the same intent and pending intent
    Intent intent = new Intent(context//same activity should be used when canceling the alarm
            , AlarmReceiver.class);
    intent.setAction("android.intent.action.NOTIFY");

    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1001, intent, 0);

    alarmManager.cancel(pendingIntent);
    pendingIntent.cancel();

}

这很有魅力。关键是,对我来说,如果我使用 FLAG_CANCEL_CURRENT 我无法取消警报。当我删除标志并在我的代码中传入0时,我可以成功删除警报。 我不确定其他标志,因为我没有尝试过。您也可以尝试更改标志或删除它们。

所以,我发现我需要使用ACTION_DISMISS_ALARM而不是ACTION_SET_ALARM。它可以让您取消闹钟中已经设置的闹钟。

答案 here, here, and 建议取消 PendingIntent,它对我不起作用,也未确认对问题作者有效。

我认为,为什么从 AlarmManager 取消 PendingIntent 不起作用的解释可能是 PendingIntent 可以让您做某事或稍后发送意图。一旦你已经完成它(已经发送了意图)你就不能撤消它。例如,您可以取消通知,但无法撤消从通知(执行的意图或操作)打开应用程序,因为它已经完成。此外,就我而言,这是我需要解除警报的另一个应用程序,所以也许我不应该期望能够撤消该操作。 因此,为了关闭或取消警报,您需要使用操作 ACTION_DISMISS_ALARM.

发送一个新的意图

按如下方式替换 try/catch 块可以为我正确设置和取消警报:

try {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
        return;
    }
    Thread.sleep(15000);
    Intent ci = new Intent(AlarmClock.ACTION_DISMISS_ALARM);
    ci.setData(i.getData());
    alarmIntent = PendingIntent.getActivity(this, 0, ci, 0);
    alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime(),
                alarmIntent);
    Log.i(TAG, "Alarm cancelled");
} catch (InterruptedException e) {
    e.printStackTrace();
}

但是,这仅适用于 API 级别 23+,并且不会像 ACTION_SET_ALARM 那样让你 SKIP_UI。