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

Android AlarmManager重启后立即触发:如何配置为仅年末执行?

解决AlarmManager重启后立即触发的问题

你现在的核心问题是把「年末清理的BroadcastReceiver」和「开机广播处理逻辑」混在一起了!你的FullYearCleaning注册了BOOT_COMPLETED等开机相关的Action,导致设备重启后,系统发送的开机广播直接触发了这个Receiver的清理操作——这根本不是AlarmManager触发的,完全偏离了你的预期。

下面是分步解决方案,帮你实现「重启后待命,仅年末触发」的流程:


步骤1:拆分职责,创建专门的开机广播Receiver

把「开机后重新设置闹钟」和「执行年末清理」的职责分开,不要让同一个Receiver干两件事。

新建一个BootCompletedReceiver类,专门负责开机后重新配置年末闹钟:

public class BootCompletedReceiver extends BroadcastReceiver {
    @Inject GeneralStorageHelper generalStorageHelper;
    @Inject MainPresenter presenter;

    @Override
    public void onReceive(Context context, Intent intent) {
        // 只处理开机相关的广播
        String action = intent.getAction();
        if (Intent.ACTION_BOOT_COMPLETED.equals(action) || 
            "android.intent.action.QUICKBOOT_POWERON".equals(action) ||
            "com.htc.intent.action.QUICKBOOT_POWERON".equals(action)) {
            AndroidInjection.inject(this, context);
            setupYearEndAlarm(context);
        }
    }

    private void setupYearEndAlarm(Context context) {
        AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, FullYearCleaning.class);
        
        // 适配Android 12+的PendingIntent flag要求
        int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? 
                    PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_CANCEL_CURRENT;
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, flags);

        Calendar calendar = Calendar.getInstance();
        // 注意:用HOUR_OF_DAY(24小时制)替代HOUR(12小时制),避免时间设置错误
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.DATE, 31);
        calendar.set(Calendar.MONTH, Calendar.DECEMBER); // 用常量替代硬编码11,可读性更强

        // 关键判断:如果当前时间已经过了今年年末,就把闹钟设置到明年
        Calendar now = Calendar.getInstance();
        if (now.after(calendar)) {
            calendar.add(Calendar.YEAR, 1);
        }

        presenter.putIntInStorage(YEAR, calendar.get(Calendar.YEAR));
        // 适配Doze模式,API23+用setExactAndAllowWhileIdle确保准时触发
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            manager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pi);
        } else {
            manager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pi);
        }
    }
}

步骤2:精简FullYearCleaning的职责

让它只负责处理AlarmManager触发的清理操作,移除所有开机相关的Action:

public class FullYearCleaning extends BroadcastReceiver {
    private static final String TAG = "FullYearCleaning";
    @Inject GeneralStorageHelper generalStorageHelper;
    @Inject CountryDaoModel countryDaoModel;

    @Override
    public void onReceive(Context context, Intent intent) {
        AndroidInjection.inject(this, context);
        Log.d(TAG, "Running ending event!");
        countryDaoModel.clearCountriesValues();
        generalStorageHelper.putIntIntStorage(SP_HALF_YEAR, NO_HALF_YEAR_NOTIFICATION);
        generalStorageHelper.putIntIntStorage(SP_COMPLETE_YEAR, NO_ALL_YEAR_NOTIFICATION);
        
        // 可选:清理完成后自动设置下一年的闹钟,避免设备一年未重启的情况
        // setupYearEndAlarm(context); // 把setup方法抽成公共工具类即可复用
    }
}

步骤3:更新Manifest配置

  1. 添加开机广播权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  1. 修改Receiver注册,拆分两个Receiver的职责:
<!-- 年末清理Receiver:无需intent-filter,因为通过显式PendingIntent触发 -->
<receiver android:name=".model.FullYearCleaning" android:enabled="true" />

<!-- 开机广播Receiver:负责重启后重新设置闹钟 -->
<receiver android:name=".model.BootCompletedReceiver" android:enabled="true" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED"/>
        <action android:name="android.intent.action.QUICKBOOT_POWERON"/>
        <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
    </intent-filter>
</receiver>

步骤4:修复原代码的两个细节问题

  1. 时间字段错误:原代码用Calendar.HOUR(12小时制)设置23点,会导致时间逻辑混乱,改用Calendar.HOUR_OF_DAY(24小时制)才正确。
  2. 未处理跨年场景:如果当前时间已过当年12月31日,直接设置当年年末会变成过去的时间,AlarmManager会立即触发,新增判断逻辑后会自动设置到次年。

最终流程

设备重启 → BootCompletedReceiver收到开机广播 → 重新计算并设置年末闹钟 → 闹钟进入后台待命 → 年末时间到达 → AlarmManager触发FullYearCleaning执行清理操作,完全符合你的预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:24:17