You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何取消次日的AlarmManager?关于AlarmManager的两项功能实现求助

Android AlarmManager 每日重复闹钟与次日闹钟取消实现方案

一、设置无限重复的每日闹钟

替代原7天限制,实现每日自动重复直到用户手动停止,核心思路是每次闹钟触发后自动设置次日的闹钟,避免系统重复闹钟的精度问题:

1. 定义闹钟广播接收器

创建AlarmReceiver处理闹钟触发逻辑,并在触发后自动设置下一日的闹钟:

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 这里写闹钟触发后的业务逻辑(如弹出通知、执行任务)
        triggerAlarmTask(context);

        // 自动设置下一日的闹钟
        setupNextDayAlarm(context, 8, 0); // 示例:每日8点触发
    }

    private void triggerAlarmTask(Context context) {
        // 自定义闹钟任务逻辑
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        // ... 构建并发送通知
    }
}

2. 初始化首次闹钟

计算首次触发时间(若当前已过目标时间则设为次日),并设置精确闹钟:

public void setupDailyAlarm(Context context, int targetHour, int targetMinute) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, targetHour);
    calendar.set(Calendar.MINUTE, targetMinute);
    calendar.set(Calendar.SECOND, 0);

    // 若当前时间已过目标时间,自动顺延至次日
    if (calendar.getTimeInMillis() < System.currentTimeMillis()) {
        calendar.add(Calendar.DAY_OF_YEAR, 1);
    }

    long alarmTime = calendar.getTimeInMillis();
    // 用日期戳生成唯一requestCode,方便后续精准取消
    int requestCode = (int) (alarmTime / (1000 * 3600 * 24));

    Intent intent = new Intent(context, AlarmReceiver.class);
    intent.putExtra("ALARM_DATE", getDateString(calendar));
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
            context,
            requestCode,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
    );

    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    // Android 12+需申请SCHEDULE_EXACT_ALARM权限
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        if (alarmManager.canScheduleExactAlarms()) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
        } else {
            // 跳转至权限申请页
            Intent permissionIntent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
            context.startActivity(permissionIntent);
        }
    } else {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
    }
}

private String getDateString(Calendar calendar) {
    return calendar.get(Calendar.YEAR) + "-" + (calendar.get(Calendar.MONTH)+1) + "-" + calendar.get(Calendar.DAY_OF_MONTH);
}

二、取消次日闹钟并保留后续每日闹钟

核心是精准定位次日闹钟的PendingIntent,取消后手动设置下下一日的闹钟,保证后续循环不中断:

public void cancelNextDayAlarm(Context context, int targetHour, int targetMinute) {
    // 计算次日的时间
    Calendar nextDay = Calendar.getInstance();
    nextDay.add(Calendar.DAY_OF_YEAR, 1);
    nextDay.set(Calendar.HOUR_OF_DAY, targetHour);
    nextDay.set(Calendar.MINUTE, targetMinute);
    nextDay.set(Calendar.SECOND, 0);

    long nextAlarmTime = nextDay.getTimeInMillis();
    int requestCode = (int) (nextAlarmTime / (1000 * 3600 * 24));

    // 创建与设置时完全一致的Intent,用于匹配PendingIntent
    Intent intent = new Intent(context, AlarmReceiver.class);
    intent.putExtra("ALARM_DATE", getDateString(nextDay));
    PendingIntent pendingIntent = PendingIntent.getBroadcast(
            context,
            requestCode,
            intent,
            PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE
    );

    if (pendingIntent != null) {
        // 取消次日闹钟
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(pendingIntent);
        pendingIntent.cancel();

        // 设置下下一日的闹钟,维持后续每日循环
        Calendar dayAfterNext = Calendar.getInstance();
        dayAfterNext.add(Calendar.DAY_OF_YEAR, 2);
        dayAfterNext.set(Calendar.HOUR_OF_DAY, targetHour);
        dayAfterNext.set(Calendar.MINUTE, targetMinute);
        dayAfterNext.set(Calendar.SECOND, 0);

        long dayAfterNextTime = dayAfterNext.getTimeInMillis();
        int dayAfterNextCode = (int) (dayAfterNextTime / (1000 * 3600 * 24));

        Intent nextIntent = new Intent(context, AlarmReceiver.class);
        nextIntent.putExtra("ALARM_DATE", getDateString(dayAfterNext));
        PendingIntent nextPendingIntent = PendingIntent.getBroadcast(
                context,
                dayAfterNextCode,
                nextIntent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && alarmManager.canScheduleExactAlarms()) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, dayAfterNextTime, nextPendingIntent);
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, dayAfterNextTime, nextPendingIntent);
        }
    }
}

关键注意事项

  • Android 12及以上版本必须申请SCHEDULE_EXACT_ALARM权限,否则无法设置精确闹钟;
  • 使用日期戳作为requestCode,确保每个日期的闹钟PendingIntent唯一,避免误取消;
  • 手动停止功能只需遍历所有已记录的requestCode,逐个取消对应的PendingIntent即可。

内容的提问来源于stack exchange,提问作者Mehar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 02:05:55