Android Alarm Manager仅触发一次,无法每5分钟重复触发问题求助
问题分析与解决方案
你的Alarm Manager仅触发一次的核心原因是未在每次触发后重新调度下一次闹钟,同时存在几个关键的代码错误,以下是具体修复步骤:
1. 核心问题梳理
setExactAndAllowWhileIdle是单次闹钟,不会自动重复,必须在每次触发后手动设置下一次- MainActivity中给Intent Action添加了
System.currentTimeMillis(),导致每次Intent唯一,无法匹配广播接收器的过滤规则 - 广播接收器未处理BOOT_COMPLETED的过滤规则,重启后无法恢复闹钟
- Android 13+需要动态申请
SCHEDULE_EXACT_ALARM权限
2. 修复后的代码
MainActivity.java
private void setAlarm() { // 检查Android 13+的精确闹钟权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { AlarmManager alarmManager = getSystemService(AlarmManager.class); 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, LocationAlarmReceiver.class); intent.setAction("com.mhz.evs.ACTION_FETCH_LOCATION"); // 固定Action,匹配广播过滤规则 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); long interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 3; // 5分钟间隔 long triggerAtMillis = System.currentTimeMillis() + interval; if (alarmManager != null) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); } }
LocationAlarmReceiver.java
public class LocationAlarmReceiver extends BroadcastReceiver { private static final String ACTION_FETCH_LOCATION = "com.mhz.evs.ACTION_FETCH_LOCATION"; @Override public void onReceive(Context context, Intent intent) { if (intent.getAction() == null) return; switch (intent.getAction()) { case Intent.ACTION_BOOT_COMPLETED: // 设备重启后设置第一次闹钟 setNextAlarm(context); break; case ACTION_FETCH_LOCATION: Toast.makeText(context, "Triggered", Toast.LENGTH_SHORT).show(); Intent serviceIntent = new Intent(context, LocationService.class); // Android O+必须使用前台服务 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } // 重新调度下一次闹钟 setNextAlarm(context); break; } } // 封装设置下一次闹钟的逻辑 private void setNextAlarm(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, LocationAlarmReceiver.class); intent.setAction(ACTION_FETCH_LOCATION); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); long interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 3; long triggerAtMillis = System.currentTimeMillis() + interval; if (alarmManager != null) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); } } }
AndroidManifest.xml
<uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <uses-permission android:name="android.permission.USE_EXACT_ALARM"/> <!-- Android O+前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <receiver android:name=".Receivers.LocationAlarmReceiver" android:exported="true" android:enabled="true"> <intent-filter> <action android:name="com.mhz.evs.ACTION_FETCH_LOCATION"/> <action android:name="android.intent.action.BOOT_COMPLETED"/> <!-- 添加BOOT_COMPLETED过滤 --> </intent-filter> </receiver> <service android:name=".Services.LocationService" android:exported="true" android:enabled="true"/>
3. 关键修复说明
- 移除动态Action后缀:使用固定的Action字符串,确保广播接收器能正确匹配Intent
- 每次触发后重新调度:在
onReceive中处理完定位逻辑后,调用setNextAlarm设置下一次闹钟 - 替换setRepeating:
setRepeating在Android 6+的Doze模式下不可靠,改用setExactAndAllowWhileIdle保证精确触发 - 添加BOOT_COMPLETED过滤:确保设备重启后能重新初始化闹钟
- 动态权限申请:Android 13+需要用户授权精确闹钟权限,否则无法调度
内容的提问来源于stack exchange,提问作者Rafay Rao
相关产品推荐
相关产品推荐

