You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让AlarmManager的setExactAndAllowWhileIdle实现重复触发?

好问题!确实从Android 6.0的Doze模式开始,普通的重复闹钟会被系统限制,而setExactAndAllowWhileIdle虽然能突破Doze限制,但只能触发一次。不过我们可以通过每次触发完成后重新设置下一次闹钟的方式,模拟出“重复触发”的效果,完美适配低功耗空闲模式。

下面给你具体的实现方案:

核心思路

放弃setRepeating,改用setExactAndAllowWhileIdle设置单次闹钟,然后在广播接收器的onReceive方法里,处理完当前业务后,立即计算下一次触发时间并重新设置闹钟,以此实现循环触发。

步骤1:修改初始闹钟设置代码

把你原来的setRepeating替换成setExactAndAllowWhileIdle,适配不同Android版本:

// 获取当前时间并设置第一次触发时间(1分钟后)
Calendar cal2 = Calendar.getInstance();
cal2.add(Calendar.MINUTE, 1);

Intent intentTracking = new Intent(getApplicationContext(), TrackingAlarmReceiver.class);
// 注意Android 12+需要添加FLAG_IMMUTABLE,避免PendingIntent异常
PendingIntent sender3 = PendingIntent.getBroadcast(
        getApplicationContext(), 
        192839, 
        intentTracking, 
        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);

AlarmManager am3 = (AlarmManager) getSystemService(ALARM_SERVICE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    // Android 6.0及以上,使用能突破Doze的setExactAndAllowWhileIdle
    am3.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), sender3);
} else {
    // 低版本设备可以直接用setRepeating或者setExact
    am3.setRepeating(AlarmManager.RTC_WAKEUP, cal2.getTimeInMillis(), 
                     Integer.parseInt(carerTrackingInteval) * 60000, sender3);
}

步骤2:修改广播接收器TrackingAlarmReceiver

在接收器里完成业务逻辑后,立即设置下一次闹钟:

public class TrackingAlarmReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 1. 先执行你的核心业务逻辑(比如追踪任务)
        executeTrackingTask();

        // 2. 计算下一次触发的时间(这里用你定义的间隔时间)
        long intervalMillis = Integer.parseInt(carerTrackingInteval) * 60000;
        long nextTriggerTime = System.currentTimeMillis() + intervalMillis;

        // 3. 重新设置下一次的闹钟
        Intent nextIntent = new Intent(context, TrackingAlarmReceiver.class);
        PendingIntent nextSender = PendingIntent.getBroadcast(
                context, 
                192839, 
                nextIntent, 
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );

        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextTriggerTime, nextSender);
        } else {
            am.setExact(AlarmManager.RTC_WAKEUP, nextTriggerTime, nextSender);
        }
    }

    private void executeTrackingTask() {
        // 这里写你的追踪业务代码,注意不要做耗时操作
        // 如果任务耗时,建议启动前台服务处理,避免被系统杀死
    }
}

关键注意事项

  • Doze模式的频率限制:即使使用setExactAndAllowWhileIdle,系统在Doze模式下也会限制这类闹钟的触发频率(通常每15分钟最多一次,不同版本有差异),这是系统的功耗保护机制,无法完全绕过。如果需要更高频的触发,建议考虑WorkManager的PeriodicWorkRequest,它会尽量在系统维护窗口执行任务。
  • 开机重启恢复:记得申请RECEIVE_BOOT_COMPLETED权限,并在开机广播接收器里重新初始化闹钟,避免设备重启后闹钟丢失。
  • 耗时任务处理:广播接收器的生命周期很短,不要在onReceive里执行耗时操作,复杂任务建议启动前台服务完成。

内容的提问来源于stack exchange,提问作者turtleboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:48:30