一、AlarmManager 是什么?

AlarmManager 是 Android 提供的一个系统服务,主要用于在未来某个时间点触发任务。

它不是普通的定时器,而是由系统统一管理的时间调度机制。App 设置一个闹钟任务后,即使 App 进程暂时不在前台,系统也可以在合适的时间触发对应操作。

常见使用场景有:

  1. 闹钟提醒

  2. 日历提醒

  3. 指定时间发送通知

  4. 到点执行一次任务

  5. App 进程不活跃时仍希望触发某个操作

获取方式如下:

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

它的核心思想是:

App 不自己一直运行计时,而是把“未来某个时间点要做什么”交给系统。

二、AlarmManager 和普通定时器的区别

方案

特点

适合场景

Handler.postDelayed()

依赖当前进程和线程

页面内短时间延迟任务

Timer

Java 层定时器,依赖进程存活

简单内存任务

AlarmManager

系统级时间触发,可以跨进程生命周期

闹钟、提醒、定时通知

WorkManager

持久化后台任务,不保证精确时间

可延迟后台任务、同步任务

所以,AlarmManager 更适合“到某个时间点触发”的任务,而不是普通后台轮询。

三、AlarmManager 的基本工作流程

flowchart TD A["App 设置闹钟"] --> B["创建 PendingIntent"] B --> C["交给 AlarmManager"] C --> D["系统保存调度信息"] D --> E["到达触发时间"] E --> F["系统触发 PendingIntent"] F --> G["BroadcastReceiver / Activity / Service 处理任务"]

这里最关键的是 PendingIntent

AlarmManager 到时间后并不是直接调用你的某个方法,而是触发你提前准备好的 PendingIntent。这个 PendingIntent 可以指向:

  1. BroadcastReceiver

  2. Activity

  3. Service

实际开发中,最常见的是触发 BroadcastReceiver,然后在广播里发送通知或继续安排下一次任务。

四、AlarmManager 的时间类型

AlarmManager 设置闹钟时,需要指定时间类型。

类型

是否基于系统时间

是否唤醒设备

说明

RTC

使用真实时间,受用户修改系统时间影响

RTC_WAKEUP

到指定真实时间后可唤醒设备

ELAPSED_REALTIME

使用开机后经过时间,不受系统时间修改影响

ELAPSED_REALTIME_WAKEUP

使用开机后经过时间,并可唤醒设备

一般可以这样选:

  1. 如果是“明天早上 8 点提醒我”,用 RTC_WAKEUP

  2. 如果是“10 分钟后执行”,用 ELAPSED_REALTIME_WAKEUP

  3. 如果不需要唤醒设备,可以不用 _WAKEUP 类型。

五、常用设置方法

方法

是否精确

是否可在 Doze 下尽量触发

适合场景

set()

不精确

普通延迟任务

setWindow()

在时间窗口内触发

可接受一定范围延迟的任务

setExact()

较精确

不一定

需要较准时触发的任务

setAndAllowWhileIdle()

不精确

Doze 下仍希望触发,但不要求精确

setExactAndAllowWhileIdle()

较精确

强时间要求的提醒

setAlarmClock()

精确

真正的闹钟类功能

Android 官方也强调,精确闹钟会明显影响系统资源和电量,所以只应该用于用户明确感知、确实需要准时触发的场景,例如闹钟、日历提醒等。Android Schedule alarms 文档

六、为什么 AlarmManager 不一定准时?

从 Android 4.4 开始,系统会对普通闹钟进行批处理。

也就是说,多个 App 的闹钟可能会被系统合并到相近时间一起触发,这样可以减少设备频繁唤醒,从而节省电量。

从 Android 6.0 开始,系统又引入了 Doze 模式。设备长时间息屏静置后,系统会限制后台任务,普通 Alarm 可能被推迟执行。

所以:

  1. set() 不保证准时。

  2. setExact()set() 更精确,但仍可能受低电耗策略影响。

  3. setExactAndAllowWhileIdle() 可以在 Doze 下尽量触发,但不能滥用。

  4. setAlarmClock() 优先级最高,适合真正的用户闹钟。

七、Android 12 之后的精确闹钟权限

从 Android 12 开始,精确闹钟受到权限限制。

如果 App 要使用这些精确闹钟 API,可能需要声明或申请相关权限:

  1. setExact()

  2. setExactAndAllowWhileIdle()

  3. setAlarmClock()

Android 14 开始,对于大多数新安装、目标版本为 Android 13 及以上的 App,SCHEDULE_EXACT_ALARM 默认不会预授予。如果没有权限,调用相关 API 可能会抛出 SecurityExceptionAndroid 14 精确闹钟变更

实际开发中,应该先判断:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    if (alarmManager.canScheduleExactAlarms()) {
        // 可以设置精确闹钟
    } else {
        // 引导用户去系统设置页开启权限
    }
}

注意:这个权限不是普通运行时权限,不能像相机、定位那样直接弹系统授权框,而是需要引导用户进入系统设置页开启。

八、AlarmManager 和 WorkManager 的区别

对比项

AlarmManager

WorkManager

核心目标

按时间点触发

执行可延迟后台任务

是否保证精确时间

可以尽量精确

不保证精确

是否支持任务链

不直接支持

支持

是否支持约束条件

很弱

支持网络、充电、电量等约束

是否适合后台同步

不推荐

推荐

是否适合闹钟提醒

推荐

不推荐

简单记:

要“几点几分提醒”,用 AlarmManager。
要“有网时同步数据”,用 WorkManager。

比如:

  1. 每天早上 8 点提醒用户喝水:AlarmManager

  2. 网络恢复后上传日志:WorkManager

  3. 低电量时暂停,充电后同步数据:WorkManager

  4. 用户设置一个倒计时提醒:AlarmManager

九、开发中容易踩的坑

  1. 以为 set() 一定准时

set() 只是普通闹钟,系统可能会延迟触发。

  1. 滥用 setExactAndAllowWhileIdle()

这个 API 会影响省电策略,只适合强提醒场景。

  1. 忘记取消闹钟

取消闹钟时,需要使用和设置时匹配的 PendingIntent

  1. 忘记处理设备重启

设备重启后,之前设置的 Alarm 通常会丢失。如果业务需要保留提醒,需要监听开机广播,然后重新注册。

  1. 把 AlarmManager 当后台任务框架使用

AlarmManager 只负责“到时间触发”,不负责任务状态、重试、任务链、约束条件。复杂后台任务应该交给 WorkManager。

十、总结

AlarmManager 是 Android 的系统级定时触发服务,适合处理和“具体时间点”强相关的任务。

它的核心价值不是让 App 自己一直计时,而是把定时触发交给系统统一管理。

学习 AlarmManager 时,可以抓住三句话:

  1. AlarmManager 是系统服务,负责未来时间点触发任务。

  2. 它通常通过 PendingIntent 触发 BroadcastReceiverActivityService

  3. 越精确的闹钟,系统限制越多,也越需要谨慎使用。

实际开发选型时:

场景

推荐方案

闹钟、日历、定时提醒

AlarmManager

后台同步、上传、重试任务

WorkManager

页面内短时间延迟

Handler / 协程延迟

前台持续任务

Foreground Service

一句话总结:

AlarmManager 不是普通定时器,而是 Android 提供的系统级时间触发机制;它适合做提醒和闹钟,不适合做普通后台任务调度。