Android 9每日8点触发通知问题:AlarmManager与WorkManager失效求助
解决Android 9+每日8点后台通知失效问题
嘿,这个问题我太熟悉了——Android 9+对后台任务的限制比之前严格多了,你的代码在低版本正常但高版本失效,主要是因为旧的AlarmManager.setRepeating()已经不适应新的系统规则了。我给你两个靠谱的解决方案,一步步来:
问题根源
Android 8.0(API 26)引入了后台执行限制,Android 9.0进一步收紧了后台任务调度:
setRepeating()在高版本中不再保证精确触发,系统会批量调度以节省电量- 当应用被完全杀死后,普通的重复闹钟会被系统直接移除
- 你原来的代码没有适配Android 12+的
PendingIntentflag要求(必须指定FLAG_IMMUTABLE或FLAG_MUTABLE)
方案1:适配高版本的AlarmManager实现
改用AlarmManager.setExactAndAllowWhileIdle(),这是系统允许的高优先级调度,即使应用被杀死或处于低电模式也能生效。注意这个方法是单次触发,所以需要在广播接收器中重新设置下一次的闹钟。
步骤1:修改闹钟初始化代码
Intent intent = new Intent(this, AppStartReceiver.class); // 适配Android 12+的PendingIntent flag要求 int pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { pendingIntentFlags |= PendingIntent.FLAG_IMMUTABLE; } PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 99, intent, pendingIntentFlags); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); long nextTriggerTime = calendar.getTimeInMillis(); // 如果当前时间已过8点,设置为明天的8点 if (System.currentTimeMillis() > nextTriggerTime) { nextTriggerTime += 24 * 60 * 60 * 1000; } // 根据系统版本选择合适的API if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent); } else { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, nextTriggerTime, 24 * 60 * 60 * 1000, pendingIntent); }
步骤2:在广播接收器中重置闹钟
修改你的AppStartReceiver,在触发通知后立即设置第二天的闹钟:
public class AppStartReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 执行通知逻辑 sendDailyNotification(context); // 重置第二天的闹钟 resetDailyAlarm(context); } private void resetDailyAlarm(Context context) { Intent intent = new Intent(context, AppStartReceiver.class); int pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { pendingIntentFlags |= PendingIntent.FLAG_IMMUTABLE; } PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 99, intent, pendingIntentFlags); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); // 设置为第二天的8点 long nextTriggerTime = calendar.getTimeInMillis() + 24 * 60 * 60 * 1000; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent); } else { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, nextTriggerTime, 24 * 60 * 60 * 1000, pendingIntent); } } private void sendDailyNotification(Context context) { // Android 8.0+必须创建通知渠道 NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("daily_alarm", "每日通知", NotificationManager.IMPORTANCE_DEFAULT); notificationManager.createNotificationChannel(channel); } NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "daily_alarm") .setSmallIcon(R.drawable.ic_notification) .setContentTitle("每日提醒") .setContentText("现在是上午8点啦") .setPriority(NotificationCompat.PRIORITY_DEFAULT); notificationManager.notify(1, builder.build()); } }
步骤3:清单文件配置广播接收器
确保在AndroidManifest.xml中正确注册接收器:
<receiver android:name=".AppStartReceiver" android:exported="false"> </receiver>
方案2:使用WorkManager(更推荐的后台调度方式)
WorkManager是Google官方推荐的后台任务调度方案,自动适配所有系统版本,即使应用被杀死或设备重启也能执行任务。
步骤1:创建Worker类
public class DailyAlarmWorker extends Worker { public DailyAlarmWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { // 发送每日通知 sendDailyNotification(getApplicationContext()); return Result.success(); } private void sendDailyNotification(Context context) { // 和广播接收器中的通知逻辑一致 NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("daily_alarm", "每日通知", NotificationManager.IMPORTANCE_DEFAULT); notificationManager.createNotificationChannel(channel); } NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "daily_alarm") .setSmallIcon(R.drawable.ic_notification) .setContentTitle("每日提醒") .setContentText("现在是上午8点啦") .setPriority(NotificationCompat.PRIORITY_DEFAULT); notificationManager.notify(1, builder.build()); } }
步骤2:调度每日任务
在应用启动时(比如Application的onCreate或主页面的onCreate)提交任务:
// 计算到下一个8点的延迟时间 Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); long now = System.currentTimeMillis(); long initialDelay = calendar.getTimeInMillis() - now; if (initialDelay < 0) { // 当前时间已过8点,延迟到明天的8点 initialDelay += 24 * 60 * 60 * 1000; } // 创建周期性任务,间隔24小时 PeriodicWorkRequest dailyWorkRequest = new PeriodicWorkRequest.Builder(DailyAlarmWorker.class, 24, TimeUnit.HOURS) .setInitialDelay(initialDelay, TimeUnit.MILLISECONDS) .setConstraints(new Constraints.Builder() .setRequiresDeviceIdle(false) // 不需要设备空闲,确保到点触发 .setRequiresBatteryNotLow(false) // 允许低电模式下运行 .build()) .setPersisted(true) // 设备重启后仍会执行 .build(); // 提交唯一任务,避免重复创建 WorkManager.getInstance(this).enqueueUniquePeriodicWork( "DailyAlarm", ExistingPeriodicWorkPolicy.REPLACE, dailyWorkRequest );
关键注意事项
- PendingIntent Flag:Android 12+必须指定
FLAG_IMMUTABLE或FLAG_MUTABLE,否则会抛出异常 - 通知渠道:Android 8.0+必须创建通知渠道才能发送通知
- 后台权限:Android 13+需要申请
POST_NOTIFICATIONS权限 - 厂商定制系统:小米、华为等厂商的系统会额外限制后台任务,建议引导用户将应用加入电池优化白名单
内容的提问来源于stack exchange,提问作者RK191
相关产品推荐
相关产品推荐

