设备重启后Alarm Manager异常:每5分钟定时闹钟仅首次触发
解决AlarmManager重启后仅触发一次的问题
嘿,这个问题我之前也碰到过,其实核心原因是Android设备重启后,所有通过AlarmManager设置的闹钟都会被系统清掉,再加上不同API版本的限制,才导致重启后只触发一次就没动静了。我给你一步步拆解解决方案:
一、补上开机重启的权限和广播接收器
首先得让应用在设备启动完成后自动重新注册闹钟,这一步是关键:
- 添加开机权限
在AndroidManifest.xml里加上这个权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
- 编写开机广播接收器
创建一个BootReceiver类,专门负责开机后重新设置闹钟:
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 确认是开机完成的广播 if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { // 调用设置闹钟的方法 setupAlarm(context); } } private void setupAlarm(Context context) { int DATA_FETCHER_RC = 123; AlarmManager mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, Receiver.class); // 适配不同API版本的PendingIntent Flag int flags; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { flags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE; } else { flags = PendingIntent.FLAG_UPDATE_CURRENT; } PendingIntent pendingIntent = PendingIntent.getBroadcast(context, DATA_FETCHER_RC, intent, flags); long interval = 5 * 60 * 1000; // 5分钟间隔 long triggerAtMillis = System.currentTimeMillis() + interval; // 适配不同API版本的闹钟设置方式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 适配Doze模式,用setExactAndAllowWhileIdle mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // API19+ 用setExact保证精度 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); } else { // 旧版本可以用setRepeating mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, interval, pendingIntent); } } }
- 在Manifest中注册接收器
把BootReceiver注册到AndroidManifest.xml中,确保系统能识别:
<receiver android:name=".BootReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- 适配部分快速开机的机型 --> <action android:name="android.intent.action.QUICKBOOT_POWERON" /> </intent-filter> </receiver>
二、修改闹钟接收器,每次触发后重新设置下一次闹钟
从Android 4.4(API19)开始,setRepeating不再保证精确的重复间隔,系统会为了省电调整闹钟时间,而且一旦设备重启或者应用被杀死,重复闹钟就会丢失。所以最好的做法是每次闹钟触发后,手动设置下一次的闹钟:
修改你的Receiver类:
public class Receiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 先执行你的数据获取逻辑 fetchYourData(); // 立即设置下一次的闹钟 setupNextAlarm(context); } private void setupNextAlarm(Context context) { int DATA_FETCHER_RC = 123; AlarmManager mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, Receiver.class); int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT; PendingIntent pendingIntent = PendingIntent.getBroadcast(context, DATA_FETCHER_RC, intent, flags); long interval = 5 * 60 * 1000; long triggerAtMillis = System.currentTimeMillis() + interval; // 适配不同API版本 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); } else { mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtMillis, interval, pendingIntent); } } private void fetchYourData() { // 这里写你原来的数据获取逻辑 } }
三、关键注意点
- 闹钟类型选对:一定要用
RTC_WAKEUP或者ELAPSED_REALTIME_WAKEUP,这两个类型会唤醒设备,避免设备休眠后闹钟不触发;如果用不带WAKEUP的类型,设备休眠时闹钟会被推迟到设备唤醒后才触发。 - Doze模式适配:如果你的应用需要在Doze模式下也能触发闹钟,必须用
setExactAndAllowWhileIdle或者setAndAllowWhileIdle,这两个方法可以突破Doze模式的限制,但系统会限制触发频率(大约每15分钟一次,不过5分钟的间隔系统会尽量满足)。 - PendingIntent的Flag:API31及以上必须加
FLAG_IMMUTABLE,否则会抛出异常;FLAG_UPDATE_CURRENT用来保证每次使用的是同一个PendingIntent,避免重复创建。
这样修改后,你的闹钟在设备重启后会自动重新注册,而且每次触发后都会设置下一次的闹钟,就不会出现只触发一次的问题了。
内容的提问来源于stack exchange,提问作者bujji
相关产品推荐
相关产品推荐

