Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Android Doze低电耗休眠模式

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

作者:氦客

这篇文章主要讨论了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. 低电耗模式限制

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

⚠️ 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,如果系统时间变更了,是不是闹钟在现实世界响起的时间也会变 ?

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

// 在 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

6.1 CPU 与任务执行机制**

6.2 网络与后台资源访问

6.3 闹钟与任务调度行为

6.4 Wakelock 处理

6.5 持续时间与退出机制

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的特性

7.2setExactAndAllowWhileIdle()的限制

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低电耗休眠模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文