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

Android AlarmManager应用关闭/被杀/设备休眠时闹钟不触发问题

AlarmManager后台/进程被杀后闹钟不触发修复

现有代码存在几个核心适配问题,按以下步骤修改即可覆盖应用后台、休眠、进程被杀场景:

  • PendingIntent未配置正确的可变性Flag,安卓12及以上版本系统会直接拦截未声明可变性的PendingIntent,导致广播无法触发
  • 缺少安卓13及以上版本必需的通知运行时权限,通知无法正常弹出
  • 未处理系统电池优化限制,安卓原生及国产定制ROM默认会对后台应用做进程冻结、杀死处理,AlarmManager触发后无法拉起应用组件
  • 未监听设备开机广播,设备重启、进程被强制杀死后,之前注册的闹钟任务会被系统清空,不会自动恢复
  • 未提前校验精确闹钟权限,安卓12及以上版本用户可以手动关闭应用的精确闹钟调度权限,关闭后setExact类接口会失效

1. 补全Manifest配置

在原有配置基础上补充缺失的权限、开机广播接收器:

<!-- 原有权限保留 -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 新增以下权限 -->
<!-- 安卓13+通知运行时权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- 开机广播权限,设备重启后恢复闹钟 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- 电池优化白名单权限 -->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

<!-- 原有AlarmReceiver保留 -->
<receiver
        android:name=".newAlarmBroadcast.AlarmReceiver"
        android:enabled="true"
        android:exported="false" />
<!-- 新增开机广播接收器 -->
<receiver
        android:name=".newAlarmBroadcast.BootReceiver"
        android:enabled="true"
        android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
    </intent-filter>
</receiver>

2. 修正所有PendingIntent的Flag配置

替换所有PendingIntent获取逻辑的Flag参数,适配安卓12+的可变性要求:
首先修改闹钟设置逻辑:

@SuppressLint("SimpleDateFormat")
private void setTheAlarm(long dateTime) {
    alarmManager = (AlarmManager) requireActivity().getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(requireActivity(), AlarmReceiver.class);
    // 配置正确的PendingIntent Flag
    int pendingFlag = PendingIntent.FLAG_UPDATE_CURRENT;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        pendingFlag |= PendingIntent.FLAG_IMMUTABLE;
    }
    PendingIntent pendingIntent = PendingIntent.getBroadcast(requireActivity(), Constants.ALARM_ID, intent, pendingFlag);

    // 安卓12+先校验精确闹钟权限,未授权则引导用户开启
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        if (!alarmManager.canScheduleExactAlarms()) {
            startActivity(new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM));
            return;
        }
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, dateTime, pendingIntent);
    } else {
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, dateTime, pendingIntent);
    }
}

再修改Notification类中跳转用的PendingIntent:

// 替换原有PendingIntent获取逻辑
int pendingFlag = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    pendingFlag |= PendingIntent.FLAG_IMMUTABLE;
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, id, intent, pendingFlag);

3. 处理运行时权限与电池优化

  • 在页面启动时动态申请安卓13+的通知权限:调用ActivityCompat.requestPermissions申请Manifest.permission.POST_NOTIFICATIONS,用户授权后才能正常弹出通知
  • 引导用户将应用加入电池优化白名单,避免系统杀死后台进程:
// 检查是否已加入电池优化白名单
@RequiresApi(api = Build.VERSION_CODES.M)
private boolean isInBatteryWhiteList() {
    PowerManager pm = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
    return pm.isIgnoringBatteryOptimizations(requireContext().getPackageName());
}

// 跳转申请页面
@RequiresApi(api = Build.VERSION_CODES.M)
private void requestBatteryWhiteList() {
    try {
        Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
        intent.setData(Uri.parse("package:" + requireContext().getPackageName()));
        startActivity(intent);
    } catch (Exception e) {
        // 部分定制ROM无专属申请页,跳转到应用详情页让用户手动开启自启、后台运行权限
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + requireContext().getPackageName()));
        startActivity(intent);
    }
}

4. 实现开机广播,恢复闹钟任务

设备重启、进程被强制清理后,之前注册的Alarm任务会被系统清除,需要在开机完成后重新注册所有闹钟:

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Intent.ACTION_BOOT_COMPLETED.equals(action) || Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
            // 从本地存储(Room、SP等)读取所有已设置的闹钟时间,循环调用setTheAlarm方法重新注册即可
        }
    }
}

额外注意事项

  • 广播接收器onReceive方法只有10秒左右的执行窗口,如果需要实现响铃、持续震动等长耗时逻辑,不要直接在Receiver里写,要启动前台服务处理,避免进程被系统直接掐断
  • 部分国产定制ROM(小米、华为、OPPO等)对setExactAndAllowWhileIdle接口有调用配额限制,默认单个应用每天仅能触发几次,必须引导用户在系统设置中手动给应用开启自启、后台无限制权限才能正常触发
  • 不要在广播接收器里直接启动Activity,安卓10及以上版本限制了后台启动Activity的行为,通过通知的PendingIntent跳转即可正常唤起页面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:06:23