Android Doze低电耗休眠模式 与 WorkManager详解

 更新时间:2025年09月20日 14:58:50   作者:氦客  
这篇文章主要讨论了Android Doze模式下WorkManager的任务执行限制及解决方案,Doze模式下,系统为省电会延迟后台活动,WorkManager的周期性任务最小间隔被强制设为15分钟,即使设置更短时间也会被系统替换,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

1. Doze模式下,WorkManager setInitialDelay设置小于15分钟,被系统强制到15分钟执行,怎么办 ?

Android 拥有两项省电功能,通过管理设备未连接电源时应用的行为来延长用户电池续航时间:低电耗模式 (Doze) 和应用待机模式 (App Standby)。 低电耗模式 通过延迟设备长时间未使用时应用的后台 CPU 和网络活动来降低电池消耗。 应用待机模式 延迟没有近期用户活动的应用的后台网络活动。

设备处于低电耗模式时,应用对某些耗电资源的访问会被延迟,直到维护窗口。 具体限制列在电量管理限制中。

低电耗模式和应用待机模式管理在 Android 6.0 或更高版本上运行的所有应用的行为,无论它们是否专门针对 API 级别 23。为了帮助确保为用户提供最佳体验,请在低电耗模式和应用待机模式下测试您的应用,并对您的代码进行任何必要的调整。以下部分提供详细信息。

2. 了解低电耗模式(Doze)

如果用户将设备拔下电源并长时间静置,且屏幕关闭,设备就会进入低电耗模式。在低电耗模式下,系统会尝试通过限制应用对网络和 CPU 密集型服务的访问来节省电池电量。它还会阻止应用访问网络,并延迟其作业、同步和标准闹钟。

系统会定期短暂退出低电耗模式,让应用完成其延迟的活动。在此 维护窗口 期间,系统会运行所有待处理的同步、作业和闹钟,并允许应用访问网络。

维护窗口结束后,系统会再次进入低电耗模式,暂停网络访问并延迟作业、同步和闹钟。随着时间的推移,系统安排维护窗口的频率会降低,有助于在设备未充电且长时间不活动的情况下减少电池消耗。

当用户通过移动设备、打开屏幕或连接充电器来唤醒设备时,系统会退出低电耗模式,所有应用都会恢复正常活动。

3. 低电耗模式限制

设备处于低电耗模式时,系统会对您的应用施加以下限制:

  • 暂停网络访问。
  • 忽略唤醒锁。
  • 将标准 AlarmManager 闹钟(包括 setExact() 和 setWindow())延迟到下一个维护窗口。
    • 如果您需要在低电耗模式下触发闹钟,请使用 setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()。
    • 通过 setAlarmClock() 设置的闹钟会正常触发。系统会在这些闹钟触发前不久退出低电耗模式。
  • 不执行 Wi-Fi 扫描。
  • 不允许同步适配器运行。
  • 不允许 JobScheduler 运行。

⚠️ WorkManager 内部使用 JobScheduler,因此 WorkManager 任务不会运行。

具体详见 Android Developer | doze-standby

4. Doze模式下,WorkManager 为何无法精确时间执行 ?

通过上文,我们可以知道,在Doze模式下,WorkManager 任务不会运行,只有在两个Doze间隔期间,系统会定期短暂退出低电耗模式,让应用完成其延迟的活动。在此 维护窗口 期间,系统会运行所有待处理的同步、作业和闹钟,并允许应用访问网络。 这个时候WorkManager的任务才会被执行。但是两个Doze之间休眠时间的间隔是不确定的,所以Doze模式下,WorkManager无法精确时间被执行。

且如果WorkManager.setInitialDelay设置的时间小于15分钟,会被系统强制替换为15分钟。
那如果我就想10分钟后执行,需要怎么办呢 ?

5. Doze模式下,如何精确时间执行 ?

这个时候,就需要使用AlarmManager的setExactAndAllowWhileIdle方法了。 (虽然WorkManager在Android低版本上也是用的AlarmManager,但是并没有使用AlarmManager的setExactAndAllowWhileIdle方法)

那么如何使用呢 ?

5.1 ​​声明权限​

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

5.2 调用前需验证是否已授权

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    if (!alarmManager.canScheduleExactAlarms()) {
        // 引导用户前往设置页授权
        Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivity(intent);
        return;
    }
}

5.3 创建 BroadcastReceiver​ : ​​接收闹钟触发事件

public class AlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 执行任务逻辑(如启动服务、发送通知)
        Log.d("Alarm", "Triggered at exact time!");
    }
}

别忘了注册 Receiver​

<receiver android:name=".AlarmReceiver" android:exported="false"/>

5.4 设置精确闹钟​

// 获取 AlarmManager
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// 创建 Intent 指向 BroadcastReceiver
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
    this, 0, intent, 
    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
// 设置触发时间(例如 10 分钟后)
long triggerTime = System.currentTimeMillis() + 10 * 60 * 1000;
// 根据版本选择方法
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    alarmManager.setExactAndAllowWhileIdle(
        AlarmManager.RTC_WAKEUP, // 使用 UTC 时间并唤醒设备
        triggerTime, 
        pendingIntent
    );
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
} else {
    alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
}

5.5 设置了AlarmManager,如果系统时间变更了,是不是闹钟在现实世界响起的时间也会变 ?

  • 若用户将系统时间​​调快 1 小时​​(从 9:00 改为 10:00),闹钟会​​立即触发​​(因为系统时间已达到目标值)。
  • 若将系统时间​​调慢 1 小时​​(从 10:00 改为 9:00),闹钟会​​延迟 1 小时触发​​(需等待系统时间再次达到 10:00)

可以监听系统时间变化的广播,然后更改闹钟

// 在 onResume() 中注册
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
registerReceiver(timeChangeReceiver, filter);
// 在 onPause() 中注销
unregisterReceiver(timeChangeReceiver);

5.6 STATE_DOZE和STATE_DOZE_SUSPEND,有什么区别 ?

在 Android 电源管理机制中,STATE_DOZESTATE_DOZE_SUSPEND 是两种不同的休眠状态,其核心区别在于系统资源限制的严格程度CPU活动状态。以下是两者的详细对比:

6. STATE_DOZE 和 STATE_DOZE_SUSPEND

  • STATE_DOZE(Doze 模式)
    • 首次引入于 Android 6.0(Marshmallow),目的是在设备闲置时(未充电、屏幕关闭、静止状态)减少后台活动。
    • 状态描述:系统进入低功耗状态,但CPU仍保持部分活动,周期性唤醒处理任务。
  • STATE_DOZE_SUSPEND(Doze 挂起模式)
    • 强化版省电机制,于 Android 9.0(Pie) 引入,作为 Doze 的深度扩展。
    • 状态描述:系统进入更深度的休眠,CPU 完全停止运行,仅保留最低限度的硬件唤醒能力(如传感器)。

6.1 CPU 与任务执行机制**

  • STATE_DOZE
    • CPU 未完全停止,而是周期性唤醒(维护窗口)。
    • 维护窗口间隔:初始为每 30 分钟唤醒一次,随后间隔逐渐延长(如 1 小时、2 小时)。
    • 任务处理:在维护窗口内,系统允许应用执行延迟的任务(如同步、AlarmManager 闹钟)。
  • STATE_DOZE_SUSPEND
    • CPU 完全挂起,无周期性唤醒。
    • 任务冻结:所有后台进程被强制暂停(通过 Linux cgroup 的 freezer 子系统),不再分配 CPU 时间片。
    • 唤醒条件:仅通过外部事件触发(如用户操作、高优先级闹钟 setAlarmClock())。

6.2 网络与后台资源访问

  • STATE_DOZE
    • 网络限制:禁止后台应用访问网络,仅维护窗口内开放。
    • 部分豁免:高优先级 GCM 消息、短信/电话可临时唤醒网络。
  • STATE_DOZE_SUSPEND
    • 完全断网:所有网络访问被禁止,包括 GCM 和短信(仅保留基础通信服务如通话)。
    • 硬件限制:Wi-Fi/GPS 扫描、传感器数据采集均暂停。

6.3 闹钟与任务调度行为

  • STATE_DOZE
    • 标准闹钟延迟:setExact()setWindow() 的闹钟被推迟至下一个维护窗口。
    • 豁免闹钟:setAndAllowWhileIdle()setExactAndAllowWhileIdle() 可在 Doze 下触发(但受每分钟 1 次的频率限制)。
  • STATE_DOZE_SUSPEND
    • 所有闹钟冻结:包括 AllowWhileIdle 类型的闹钟,仅 setAlarmClock()(用户可见的闹钟)可唤醒设备。
    • 任务调度失效:JobScheduler 和 WorkManager 任务被无限期推迟,直至退出 SUSPEND 状态。

6.4 Wakelock 处理

  • STATE_DOZE
    • 部分屏蔽:普通 WakeLock 被忽略(如 PARTIAL_WAKE_LOCK),但高优先级服务(如媒体播放)可能被豁免。
  • STATE_DOZE_SUSPEND
    • 完全无效:所有 WakeLock 被强制释放,无法阻止 CPU 挂起。

6.5 持续时间与退出机制

  • STATE_DOZE
    • 动态维护窗口:窗口间隔随闲置时间延长而增加(30 分钟 → 1 小时 → 数小时)。
    • 退出条件:屏幕点亮、设备移动或充电。
  • STATE_DOZE_SUSPEND
    • 持续挂起:无周期性窗口,直至外部事件唤醒。
    • 退出条件更严格:仅用户交互(如按键)、setAlarmClock() 闹钟或充电可唤醒。

6.6 对比总结

特性STATE_DOZESTATE_DOZE_SUSPEND
CPU 状态周期性唤醒(维护窗口)完全停止
网络访问仅维护窗口开放完全禁止
闹钟执行允许 AllowWhileIdle 类型setAlarmClock() 有效
任务调度维护窗口内执行完全冻结
Wakelock 有效性部分豁免全部释放
退出条件移动/亮屏/充电仅用户操作或高优先级闹钟
省电强度中度极端

6.7 适配建议

  1. 后台任务
    • 使用 WorkManagerJobScheduler,其任务在 STATE_DOZE 的维护窗口自动执行,但 STATE_DOZE_SUSPEND 中仍会被冻结。
  2. 实时性需求
    • 关键任务(如闹钟)优先用 setAlarmClock()(用户可见),或引导用户将应用加入电池优化白名单。
  3. 网络依赖
    • STATE_DOZE_SUSPEND 下网络完全不可用,需通过高优先级 GCM 消息或短信唤醒设备(系统服务如电话/SMS 始终豁免)。
  4. 状态检测
    • 通过 PowerManager.isDeviceIdleMode() 检测 Doze 状态,但无法直接区分 SUSPEND(需依赖行为推断)。

📌 核心结论
STATE_DOZE周期性唤醒的轻度休眠,适合延迟容忍的任务;
STATE_DOZE_SUSPENDCPU 完全停止的深度冻结,仅响应极高优先级事件。
开发者需针对两者设计降级策略,确保关键功能在极端省电下仍可工作。

7. STATE_DOZE_SUSPEND状态下设置setExactAndAllowWhileIdle有效吗

在 Android 的 STATE_DOZE_SUSPEND(深度挂起模式)状态下,setExactAndAllowWhileIdle() 是无效的。以下是具体原因和机制分析:

7.1STATE_DOZE_SUSPEND的特性

  • CPU 完全冻结
    此状态下系统进入深度休眠,CPU 完全停止运行,所有后台进程被强制暂停,仅保留基础硬件唤醒能力(如高优先级闹钟或物理按键)。
  • 网络与任务冻结
    所有网络访问被禁止,JobSchedulerWorkManager 等后台任务被无限期推迟,标准闹钟和 AllowWhileIdle 类闹钟均被冻结。

7.2setExactAndAllowWhileIdle()的限制

  • 仅适用于普通 Doze 模式
    setExactAndAllowWhileIdle() 设计用于 STATE_DOZE(普通休眠),可在维护窗口外触发(但受每分钟 1 次的频率限制)。但在 STATE_DOZE_SUSPEND 下,系统无周期性唤醒机制,导致该方法失效。
  • 深度省电下的唤醒条件
    仅以下事件可唤醒 STATE_DOZE_SUSPEND
    • 用户主动操作(如点亮屏幕)
    • 高优先级闹钟 setAlarmClock()(系统会提前退出休眠并显示通知)
    • 设备充电。

7.3 替代方案

若需在 STATE_DOZE_SUSPEND 下可靠触发任务,需采用以下策略:

  1. setAlarmClock()
    • 用于用户可见的精确闹钟(如闹钟应用),系统会强制退出休眠并显示通知栏图标。
    • 无需特殊权限,但用户感知明显。
  2. 引导用户加入白名单
    • 用户手动在 设置→电池优化 中将应用设为“未优化”,可部分豁免限制(非完全保障,厂商兼容性差异大)。
  3. 前台服务(Foreground Service)
    • 通过持续通知栏服务维持进程活跃性,但需合理说明用途以避免被系统限制或用户关闭。

7.4 总结:不同闹钟方法在 Doze 模式下的有效性

闹钟方法STATE_DOZE(普通休眠)STATE_DOZE_SUSPEND(深度挂起)
setExact() / setWindow()❌ 延迟至维护窗口❌ 完全冻结
setAndAllowWhileIdle()✅ 可触发(精度低)❌ 无效
setExactAndAllowWhileIdle()✅ 可触发(秒级误差)❌ 无效
setAlarmClock()✅ 立即触发✅ 强制唤醒(需用户可见通知)

结论
STATE_DOZE_SUSPEND 下,setExactAndAllowWhileIdle() 无法触发。若需极端省电模式下的可靠性,应优先使用 setAlarmClock() 或引导用户设置白名单)。

8. 更多内容

有关WorkManager基础的概念和使用,详见 : Android WorkManager的概念和使用

到此这篇关于Android Doze低电耗休眠模式 与 WorkManager详解的文章就介绍到这了,更多相关Android Doze低电耗休眠模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android studio下载安装使用SVN的方法

    Android studio下载安装使用SVN的方法

    在AndroidStudio中开发版本控制,除了Git就是SVN,和Eclipse不同,Android Studio没有提供单独的插件,只能和SVN客户端关联使用,这篇文章主要介绍了Android studio使用SVN的方法,需要的朋友可以参考下
    2022-09-09
  • Android实现页面短信验证功能

    Android实现页面短信验证功能

    这篇文章主要为大家详细介绍了Android实现页面短信验证功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • 解析Android中使用自定义字体的实现方法

    解析Android中使用自定义字体的实现方法

    本篇文章是对在Android中使用自定义字体的方法进行了详细的分析介绍。需要的朋友参考下
    2013-05-05
  • Android实现断点多线程下载

    Android实现断点多线程下载

    这篇文章主要为大家详细介绍了Android实现断点多线程下载,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • android网络图片查看器简单实现代码

    android网络图片查看器简单实现代码

    这篇文章主要为大家详细介绍了android网络图片查看器的简单实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • android 如何判断当前是否为飞行模式

    android 如何判断当前是否为飞行模式

    android 开发过程中如何判断当前是否是飞行模式和侦听airplane mode change,本文将以此问题详细介绍,需要了解的朋友可以参考下
    2012-11-11
  • Android响应事件onClick方法的五种实现方式小结

    Android响应事件onClick方法的五种实现方式小结

    本篇文章主要介绍了Android响应onClick方法的五种实现方式小结,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-03-03
  • Android中应用多进程的整理总结

    Android中应用多进程的整理总结

    Android平台支持多进程通信,也支持应用内实现多进程,下面这篇文章主要给大家介绍了关于Android中应用多进程的相关资料,文中介绍的很详细,相信对大家具有一定的参考借鉴价值,有需要的朋友们下面来一起看看吧。
    2017-01-01
  • Android Eclipse 注释模板的使用(图文说明)

    Android Eclipse 注释模板的使用(图文说明)

    为提高代码的可读性以及后期的可维护性,为我们的代码加上规范化的注释是很有必要,不仅有利于提高自己的专业素养,也能方便他人
    2013-12-12
  • Android Studio 打包生成APK文件方法

    Android Studio 打包生成APK文件方法

    Android Studio是谷歌推出一个Android集成开发工具,基于IntelliJ IDEA。这篇文章主要介绍了Android Studio 打包生成APK文件方法,需要的朋友可以参考下
    2018-07-07

最新评论