一、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 可能会抛出 SecurityException。Android 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 触发 BroadcastReceiver、Activity 或 Service。

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

实际开发选型时:

场景

推荐方案

闹钟、日历、定时提醒

AlarmManager

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

WorkManager

页面内短时间延迟

Handler / 协程延迟

前台持续任务

Foreground Service

一句话总结:

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