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

Alarm BroadcastReceiver始终未被调用问题求助

问题分析与修复方案

核心问题点

  1. 重复设置闹钟导致冲突:同时调用syncAlarm(精确闹钟)和setRepeating(非精确重复闹钟),后者会覆盖前者的设置。而setRepeating在Android 6+的Doze模式、应用前台场景下会被系统延迟或忽略,这就是前台不触发、仅解锁时触发的原因。
  2. 高版本权限未动态申请:Android 12(API 31)及以上,SCHEDULE_EXACT_ALARM权限需要用户手动授权,仅在Manifest声明无效。
  3. 冗余无效代码:syncAlarm方法内创建了新的Intent但未使用,属于无效代码。
  4. 不必要的Intent-Filter:通过显式Intent启动广播时,Manifest中的<intent-filter>完全多余,反而可能造成混淆。

修复步骤及代码修改

1. 修正Manifest配置

移除多余的<intent-filter>:

<receiver android:name=".AlertReceiver"
    android:enabled="true"
    android:exported="true"/>

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />

2. 修复MainActivity的闹钟设置逻辑

移除重复的setRepeating调用,添加动态权限检查:

private void startAlarm(Calendar c) {
    // Android 12+ 检查精确闹钟权限
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        if (!alarmManager.canScheduleExactAlarms()) {
            Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
            startActivity(intent);
            return;
        }
    }

    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(this, AlertReceiver.class);
    // 使用正确的PendingIntent Flag
    PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, 
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

    if (c.before(Calendar.getInstance())) {
        c.add(Calendar.DATE, 1);
    }

    // 仅保留精确闹钟设置
    syncAlarm(this, c.getTimeInMillis(), alarmManager, pendingIntent);
    Log.d("MainActivity", "Created Alarm");
}

private void syncAlarm(Context context, long time, AlarmManager am, PendingIntent pending) {
    // 删除无用的Intent创建代码
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pending);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        am.setExact(AlarmManager.RTC_WAKEUP, time, pending);
    } else {
        am.set(AlarmManager.RTC_WAKEUP, time, pending);
    }
}

3. 修改AlertReceiver实现重复触发逻辑

由于setExactAndAllowWhileIdle不支持重复,需要在每次广播触发后手动设置下一次闹钟:

public class AlertReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "AlertReceiver called", Toast.LENGTH_LONG).show();
        Log.d("Broadcast Receiver", "Entered onReceive");

        // 设置下一天的闹钟
        Calendar nextDay = Calendar.getInstance();
        nextDay.add(Calendar.DATE, 1);
        
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent nextIntent = new Intent(context, AlertReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, nextIntent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

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

关键说明

  • 精确闹钟的必要性:高版本Android对非精确闹钟(如setRepeating)的触发时机限制严格,仅在系统认为合适的时候才会执行,而setExactAndAllowWhileIdle可以突破Doze模式限制,保证按时触发。
  • 重复触发的替代方案:由于精确闹钟不支持重复,只能在每次广播回调中手动设置下一次的闹钟时间,实现每日重复的效果。
  • 权限处理:Android 12+必须让用户手动开启精确闹钟权限,否则无法设置成功,所以必须添加权限检查和跳转逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:15:05