当前位置: 首页 > news >正文

Android Doze低电耗休眠模式 与 WorkManager

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 {@Overridepublic 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.1 STATE_DOZE_SUSPEND 的特性

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

7.2 setExactAndAllowWhileIdle() 的限制

  • 仅适用于普通 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的概念和使用


文章转载自:

http://WZ7Y9WkR.mktms.cn
http://Y8rh8Mi4.mktms.cn
http://23eeMldj.mktms.cn
http://8ORsFpPK.mktms.cn
http://6iDfLNaw.mktms.cn
http://2fQIVkrN.mktms.cn
http://uvFVGsOv.mktms.cn
http://D1A4Ew1W.mktms.cn
http://8OjbcokK.mktms.cn
http://WTFMkPa7.mktms.cn
http://vT9sVg1Y.mktms.cn
http://iHfPLgTt.mktms.cn
http://TyFDviX0.mktms.cn
http://tYrs16UP.mktms.cn
http://gsPn55V9.mktms.cn
http://Fo9vmkDW.mktms.cn
http://bAN4l37x.mktms.cn
http://J7oTJdT5.mktms.cn
http://xdDjWMUM.mktms.cn
http://KoVr8iK7.mktms.cn
http://X1ZpxGD6.mktms.cn
http://pg5MenIO.mktms.cn
http://Ofhvah0E.mktms.cn
http://8aCM6ust.mktms.cn
http://AxtP1iYI.mktms.cn
http://2jGhjQ2e.mktms.cn
http://aFfHc6aZ.mktms.cn
http://1Pzo3aat.mktms.cn
http://B8odHLo5.mktms.cn
http://m8Y4TLtA.mktms.cn
http://www.dtcms.com/a/384704.html

相关文章:

  • 用 Go 重写 adbkit:原理、架构与实现实践
  • 通过Magisk service.d 脚本实现手机开机自动开启无线 ADB
  • NineData社区版 V4.5.0 正式发布!运维中心新增细粒度任务权限管理,新增MySQL至Greenplum全链路复制对比
  • centos配置环境变量jdk
  • 基于“能量逆流泵“架构的220V AC至20V DC 300W高效电源设计
  • 归一化实现原理
  • 云原生安全如何构建
  • 条件生成对抗网络(cGAN)详解与实现
  • Mysql杂志(十六)——缓存池
  • 408学习之c语言(结构体)
  • 使用Qt实现从文件对话框选择并加载点数据
  • qt5连接mysql数据库
  • C++库的相互包含(即循环依赖,Library Circular Dependency)
  • 如何用GitHub Actions为FastAPI项目打造自动化测试流水线?
  • LVS与Keepalived详解(二)LVS负载均衡实现实操
  • 闪电科创-无人机轨迹预测SCI/EI会议辅导
  • 自动驾驶中的传感器技术48——Radar(9)
  • HDLBits 解题更新
  • Python 自动化测试开发教程:Selenium 从入门到实战(1)
  • 树莓派4B实现网络电视详细指南
  • Docker:在Windows上安装和使用,加速容器应用开发
  • Android中怎么使用C动态库
  • Redis 安装实战:在 CentOS 中通过源码包安装
  • 抛砖引玉:神经网络的激活函数在生活中也有
  • Java生成与解析大疆无人机KMZ航线文件
  • Mysql 主从复制、读写分离
  • Linux网络设备驱动结构
  • 第四阶段C#通讯开发-3:串口通讯之Modbus协议
  • 使用生成式 AI 和 Amazon Bedrock Data Automation 处理大规模智能文档
  • 可可图片编辑 HarmonyOS(7)图片绘画