4. Doze模式的两种形态:浅度Doze与深度Doze
说到Doze模式,很多人以为它只有一个状态——手机一放,系统就进入深度省电。其实不是这样。Google从Android 7.0开始引入了两种形态:浅度Doze(Light Doze)和深度Doze(Deep Doze)。我刚开始研究这部分代码时,也以为只是简单的二段式,后来踩了几个坑才明白,这两种形态的设计逻辑完全不同。
说白了,浅度Doze是「温和提醒」,深度Doze是「强制断网」。系统会根据设备静止的时间长短,逐步收紧对App的限制。你想想看,如果手机刚放桌上两分钟就直接断网,那微信消息岂不是全收不到了?所以Google设计了两阶段策略。
4.1 浅度Doze(Light Doze)
浅度Doze是Doze模式的第一阶段。设备进入这个状态的条件比较宽松:
- 屏幕关闭超过30分钟
- 设备处于静止状态(通过加速度传感器判断)
- 未连接充电器
进入浅度Doze后,系统会做什么?我直接说结论:网络访问被限制,但闹钟和部分高优先级任务仍然可以执行。
核心行为:
- 禁止App访问网络(除非在白名单中)
- 延迟JobScheduler和AlarmManager任务
- 允许高优先级闹钟(如闹铃、日历提醒)
- 允许FCM(Firebase Cloud Messaging)高优先级消息
我记得有一次在项目中调试一个即时通讯App,发现用户在锁屏30分钟后收不到消息。排查了半天,发现是浅度Doze把网络给掐了。解决方案其实很简单——申请一个高优先级的FCM通道,或者让用户把App加入电池优化白名单。
避坑指南:
我曾经遇到过一个问题:App在浅度Doze下明明设置了AlarmManager,但就是不触发。后来查了源码才发现,AlarmManager在浅度Doze下默认会被延迟到下一个维护窗口(Maintenance Window)。如果你需要准时触发,必须使用setAlarmClock()或setExactAndAllowWhileIdle()。
4.2 深度Doze(Deep Doze)
深度Doze是更严格的省电状态。设备进入这个状态需要满足更长的静止时间——通常是屏幕关闭超过60分钟,并且设备完全静止。进入深度Doze后,系统会进入「几乎完全休眠」的状态。
嗯,这里要注意:深度Doze下,系统会进入周期性维护窗口模式。什么意思呢?就是系统每隔一段时间(通常是几分钟到几十分钟)会短暂唤醒,让所有App统一处理积压的任务。这个窗口非常短,大概只有几十秒。
| 特性 | 浅度Doze | 深度Doze |
|---|---|---|
| 触发条件 | 屏幕关闭30分钟 | 屏幕关闭60分钟+静止 |
| 网络访问 | 禁止(白名单除外) | 禁止(仅在维护窗口允许) |
| 闹钟执行 | 高优先级可执行 | 仅在维护窗口执行 |
| 维护窗口 | 无固定窗口 | 周期性短暂窗口 |
| GPS/WiFi扫描 | 频率降低 | 完全禁止 |
从表格可以看出来,深度Doze的限制比浅度严格得多。我个人习惯在测试深度Doze时,用adb shell dumpsys deviceidle force-idle deep命令直接强制进入,省得等一个小时。
4.3 两种形态的切换逻辑
系统是怎么从浅度Doze切换到深度Doze的?我画了一张流程图,方便你理解整个决策过程。
从流程图可以看到,系统会先判断是否满足30分钟静止条件。满足则进入浅度Doze,不满足则保持正常模式。在浅度Doze中继续监控,如果静止时间超过60分钟,就升级到深度Doze。深度Doze下,系统会周期性地进入维护窗口,让App有机会处理紧急任务。
注意事项:
我曾经在项目中遇到一个坑:某些厂商在定制ROM时,修改了Doze的触发时间阈值。比如某厂商把浅度Doze的触发时间从30分钟改成了15分钟。这会导致你的App在锁屏后更快被限制。所以,不要完全依赖官方文档的时间参数,最好在实际设备上测试。
4.4 两种形态对App的影响
理解了两种形态的区别,我们来看看对App开发者的实际影响:
- 浅度Doze下:你的App仍然可以接收高优先级FCM消息,但普通网络请求会被拦截。如果你需要后台定位,建议使用
WorkManager配合setExpedited()来申请紧急任务。 - 深度Doze下:几乎所有后台活动都被暂停。只有系统维护窗口期间,你的App才能执行任务。这个窗口通常只有几十秒,所以任务必须短小精悍。
我个人建议:如果你的App需要长时间后台运行(比如音乐播放、导航),一定要使用startForegroundService()并显示通知。这样系统会认为你的App处于「用户可见」状态,不会轻易进入Doze限制。
调试技巧:
用以下adb命令可以快速测试两种Doze状态:
# 强制进入浅度Doze
adb shell dumpsys deviceidle force-idle light
# 强制进入深度Doze
adb shell dumpsys deviceidle force-idle deep
# 退出Doze模式
adb shell dumpsys deviceidle unforce
# 查看当前Doze状态
adb shell dumpsys deviceidle | grep "mState"
好了,关于浅度Doze和深度Doze的区别,我们就讲到这里。记住一句话:浅度Doze是「温柔提醒」,深度Doze是「强制休眠」。理解了这个核心差异,你在做后台任务优化时就能有的放矢了。
公众号:蓝海资料掘金营,微信deep3321