惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AI
AI
TaoSecurity Blog
TaoSecurity Blog
H
Heimdal Security Blog
Help Net Security
Help Net Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Microsoft Azure Blog
Microsoft Azure Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
N
News | PayPal Newsroom
V2EX - 技术
V2EX - 技术
博客园 - 【当耐特】
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
Secure Thoughts
C
CERT Recently Published Vulnerability Notes
罗磊的独立博客
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy & Cybersecurity Law Blog
有赞技术团队
有赞技术团队
S
Schneier on Security
S
SegmentFault 最新的问题
Google Online Security Blog
Google Online Security Blog
H
Hacker News: Front Page
The Last Watchdog
The Last Watchdog
Schneier on Security
Schneier on Security
PCI Perspectives
PCI Perspectives
IT之家
IT之家
Project Zero
Project Zero
博客园 - 司徒正美
P
Privacy International News Feed
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Jina AI
Jina AI
Security Latest
Security Latest
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
C
CXSECURITY Database RSS Feed - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
C
Check Point Blog
aimingoo的专栏
aimingoo的专栏
V
Vulnerabilities – Threatpost
W
WeLiveSecurity
NISL@THU
NISL@THU
Webroot Blog
Webroot Blog
N
Netflix TechBlog - Medium
L
Lohrmann on Cybersecurity

博客园 - 邢帅杰

.net core使用SharpZipLib压缩zip文件并设置密码 CSRedisCore用法 Android 常用数据目录(内部 / 外部、缓存、文件) 的 获取方法对照表 安卓把assets中的文件copy到app目录中 oracle执行sql语句前清除缓存 安卓开发使用interface自定义回调函数 安装DockerDesktop并启用 oracle中decode用法 vue使用import.meta编译报错,import.meta.env报:类型“ImportMeta”上不存在属性“env”。必须配置module。 oracle游标使用详解 oracle存储过程中声明一个行变量,接收游标中的行数据。variable_name table_name%ROWTYPE oracle NVL和NVL2 C#获取文件md5码 oracle查询存储过程和函数中是否包含某个字符串 Android清除WebView缓存 C#获取当前日期是星期几 切换项目git地址,项目迁移到新git地址 C#线程同步、跨进程同步Mutex详解、C#只允许运行一个实例 Android Stack说明 安卓打开第三方app并传入参数 java两个日期相差秒数
安卓如何唤醒深度睡眠的设备并执行任务
邢帅杰 · 2025-05-28 · via 博客园 - 邢帅杰

在安卓系统中,深度睡眠通常指的是设备处于低功耗状态,CPU停止运行,大部分后台进程暂停,以节省电量。这时候设备不会响应一般的事件,比如通知或者网络请求,除非有特定的唤醒机制。
常见的方法可能有使用AlarmManager设置重复的定时任务,或者使用WakeLock来保持CPU运行。不过,WakeLock需要特别权限,而且不当使用会导致电池耗尽,所以需要谨慎。
如果需要在特定时间执行任务的应用,比如闹钟或者定时提醒。这时候使用AlarmManager可能更合适,特别是setExactAndAllowWhileIdle或者setAlarmClock这类方法,可以在深度睡眠时唤醒设备。
AlarmManager(精准闹钟)​适用于定时触发任务(如闹钟、定时同步数据):

    /**
     * 设置定时闹钟,唤醒深度睡眠的设备,执行任务。
     * */
    public void setAlarmManagerTask() {
        // 获取 AlarmManager 实例
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        // 创建 PendingIntent,用于在定时任务触发时执行特定的操作
        Intent intent = new Intent(this, MyBroadcastReceiver.class);
        // requestCode设置为一个特殊的数字(123456),避免和其他PendingIntent相同。
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 123456, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        //先取消,再注册,在MyBroadcastReceiver中执行任务完成后,重新调用此函数,实现定时执行任务。
        alarmManager.cancel(pendingIntent);

        // 设置定时任务,每隔一段时间唤醒设备并执行操作
        // 这里不使用System.currentTimeMillis()因为app时间和系统时间因为时区可能导致不一样。
        Date dateNow = new Date();
        // 10秒后触发定时任务。当前时间点增加10秒。
        long triggerAtMillis = dateNow.getTime() + (10 * 1000);
        // 每隔1分钟重复执行一次
        long intervalMillis = 60 * 1000;

        // 使用 RTC_WAKEUP 确保设备休眠时唤醒
        // 方式1:设置重复闹钟(经过测试,会有不准确的情况,原因是此方法会被系统调整。)
        //alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, intervalMillis, pendingIntent);

        //方式2:使用setExact和setExactAndAllowWhileIdle设置闹钟,然后在MyBroadcastReceiver中重新调用此方法注册新闹钟。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
        } else {
            alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
        }
    }

创建广播接收器
在上述代码中,我们创建了一个 BroadcastReceiver 类来处理设备唤醒后的操作。以下是一个简单的示例:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 在设备唤醒后执行的操作
        Toast.makeText(context, "设备已唤醒,任务执行中...", Toast.LENGTH_SHORT).show();
        // 重新注册闹钟,实现定时循环任务。
        setAlarmManagerTask();
    }
}

注册 BroadcastReceiver
为了使广播接收器能正常接收到定时任务触发的广播,我们还需要在 AndroidManifest.xml 文件中注册该广播接收器。
注:唤醒设备需要具有权限 android.permission.WAKE_LOCK
以下是注册广播接收器的示例代码:

<manifest xmlns:android=" package="com.example.myapp">
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <application>
        <receiver android:name=".MyBroadcastReceiver" />
    </application>
</manifest>

AlarmManager方法对比:
set()允许系统在休眠时延迟触发,以节省电量。非关键任务(如定期更新)
setExact()强制准时触发,不延迟。需要精确时间的任务
setRepeating()周期性触发,但间隔可能被系统调整。周期性任务(但不要求严格间隔)
setExactAndAllowWhileIdle()允许在 Doze 模式下立即触发(但可能增加耗电)。极端紧急任务(如报警)
取消闹钟:
创建与设置时相同的 PendingIntent,必须使用相同的 requestCode、Intent 数据和 flags。
调用 alarmManager.cancel(pendingIntent),传入对应的 PendingIntent 即可取消关联的闹钟。

alarmManager.cancel(pendingIntent);
pendingIntent.cancel(); // 清理 PendingIntent

资源管理:
务必通过 alarmManager.cancel(pendingIntent) 取消不再需要的闹钟,避免内存泄漏。
使用 PendingIntent.FLAG_UPDATE_CURRENT 或 FLAG_IMMUTABLE 确保 PendingIntent 行为可控。
PendingIntent 要执行的操作:
当闹钟触发时,系统会通过此 PendingIntent 启动目标组件(如 BroadcastReceiver 或 Service)。
必须通过 PendingIntent.getActivity()、PendingIntent.getService() 或 PendingIntent.getBroadcast() 创建。
Doze 模式兼容性:
在 Android 6.0(API 23)及以上,系统会进入 Doze 模式以延长续航,此时普通闹钟(如 setExact())可能被延迟。
setExactAndAllowWhileIdle() 会绕过 Doze 模式的限制,但频繁使用会显著增加耗电。​
触发时间限制:
在 Doze 模式下,系统可能会将多次连续的精确闹钟合并,或推迟到维护窗口执行。若需更严格的实时性(如每秒触发),需结合前台服务(ForegroundService)。

通过使用 AlarmManager 类和 BroadcastReceiver 类,我们可以实现在 Android 设备的深度休眠模式下唤醒设备并执行特定的操作。这种方法可以用于定时任务、后台数据同步等场景。希望本文能帮助你理解如何在 Android 中实现深度休眠唤醒。