安卓定时推送通知仅在应用打开时生效问题咨询
问题根因
- 你当前使用的
alarmManager.setExact()是一次性闹钟,触发后会自动失效,不会自动循环执行后续任务,所以只有首次打开App注册的那次闹钟会生效,后续没有新的闹钟注册自然不会触发 - 你写死了固定的闹钟时间为20:01,没有动态计算下一次的执行时间,就算闹钟支持重复也无法按每小时的逻辑执行
- 高版本Android存在后台限制:Android 6.0+的低电耗模式会拦截后台闹钟、Android12+要求PendingIntent必须显式指定可变性标记,国产ROM的省电策略也会默认杀死退后台的App闹钟任务
修复方案
1. 适配高版本Android的闹钟注册逻辑
修改setAlarm方法,补充PendingIntent标记和低电耗模式适配:
@RequiresApi(api = Build.VERSION_CODES.KITKAT) private void setAlarm(Calendar calendar) { AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(this, AlarmReceiver.class); // 适配Android12+的PendingIntent可变性要求,不需要修改intent内容就用FLAG_IMMUTABLE int flag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT; PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, flag); // 适配低电耗模式,保证熄屏状态下也能触发闹钟 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } else { alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } }
2. 改造广播接收器实现循环触发
每次闹钟触发完成任务后,自动注册下一小时的闹钟:
public class AlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 先执行文本文件变更检查逻辑,有变更再发通知 NotificationHelper notificationHelper = new NotificationHelper(context); NotificationCompat.Builder nb = notificationHelper.getChannelNotification(); notificationHelper.getManager().notify(1, nb.build()); // 计算下一次闹钟时间:当前时间+1小时 Calendar nextCalendar = Calendar.getInstance(); nextCalendar.add(Calendar.HOUR_OF_DAY, 1); nextCalendar.set(Calendar.MINUTE, 0); nextCalendar.set(Calendar.SECOND, 0); // 注册下一次闹钟 setNextAlarm(context, nextCalendar); } @RequiresApi(api = Build.VERSION_CODES.KITKAT) private void setNextAlarm(Context context, Calendar calendar) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, AlarmReceiver.class); int flag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT; PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, flag); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } else { alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); } } }
3. 修改初始闹钟逻辑
如果需要App启动后从当前时间开始每小时执行,修改onCreate里的初始闹钟设置:
notificationManager = NotificationManagerCompat.from(this); // 初始闹钟设为当前时间往后推1小时的整点 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.HOUR_OF_DAY, 1); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); setAlarm(calendar);
补充注意事项
国内机型需要引导用户开启App的自启动权限、后台活动权限、关闭电池优化,否则App退后台后闹钟会被系统强制拦截。
内容的提问来源于stack exchange,提问作者blocks1245
相关产品推荐
相关产品推荐

