Android Oreo:应用退出内存后Broadcast Receiver无法触发
兄弟,这个问题我之前踩过巨坑!核心原因就是Android从6.0开始引入的Doze模式、App Standby,再加上国内厂商定制ROM的激进后台清理策略——虽然AlarmManager确实触发了Intent,但系统会阻止被杀掉的应用复活来执行onReceive方法。给你几个实测有效的解决方案:
Android 12及以上版本对PendingIntent的Flag有强制要求,之前的FLAG_UPDATE_CURRENT单独用可能会出问题,建议加上FLAG_IMMUTABLE(如果不需要修改PendingIntent内容)或者FLAG_MUTABLE:
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
这个是基础,很多时候就是Flag不对导致Intent发不出去。
普通的set()方法在Doze模式下会被延迟甚至忽略,换成setExactAndAllowWhileIdle()或者setAlarmClock(),这俩能绕过Doze限制,精准触发:
long triggerTime = System.currentTimeMillis() + 60 * 1000; // 1分钟后触发 AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pi); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pi); } else { am.set(AlarmManager.RTC_WAKEUP, triggerTime, pi); }
setAlarmClock()优先级更高,还会在系统时钟显示图标,适合需要绝对精准的场景。
如果你的需求是周期性通知,别死磕AlarmManager了,WorkManager是Google专门为后台任务设计的,自动适配所有Android版本的后台限制,就算应用被杀,也能在系统允许的时机自动执行任务:
首先创建一个Worker类:
public class NotificationWorker extends Worker { public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { // 在这里写你的通知逻辑 Toast.makeText(getApplicationContext(), "Alarm !!!!!!!!!!", Toast.LENGTH_LONG).show(); return Result.success(); } }
然后调度周期性任务:
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder( NotificationWorker.class, 15, TimeUnit.MINUTES) // 注意:最小周期是15分钟 .build(); WorkManager.getInstance(context).enqueue(workRequest);
国内小米、华为、OPPO这些厂商的后台管理太狠,就算你代码写得完美,还是可能被清。所以一定要在应用里加个引导,让用户手动把你的应用加入后台白名单/电池优化豁免列表,步骤大概是:
- 打开系统设置 → 应用管理 → 找到你的应用
- 进入“电池优化”或“后台运行权限”,设置为“不允许优化”或“允许后台运行”
最后再确认下Manifest里的配置:
- Android 12+的Receiver如果接收自定义Action,必须加
android:exported="true":
<receiver android:name=".Alarm" android:exported="true"> <intent-filter> <action android:name="android.intent.action.NOTIFY" /> <action android:name="com.myApp.myCustomThing" /> </intent-filter> </receiver>
com.android.alarm.permission.SET_ALARM这个权限是给系统闹钟用的,你自己用AlarmManager的话可以删掉,没用。另外Android 13+要显示通知,得动态申请POST_NOTIFICATIONS权限,别忘了加。
别用手动划掉应用的方式测试,很多厂商划掉就是强制停止,和正常后台清理不一样。用adb命令模拟更准确:
adb shell am force-stop com.your.package.name
内容的提问来源于stack exchange,提问作者Dwarakesh Pallagolla

