App里有一个自己在Manifest文件里面注册的广播接收器(Receiver),到Android8.0
的机器上调试的时候却接收不到消息,一番搜索和研究之后,才发现Android8.0
已经对隐式广播
做了限制。
版本区别
对于targetSdkVersion
在26
或者以上的App,在Manifest
里面注册的Receiver
已经受到限制,而用Java
代码动态注册的Receiver
则不受影响。
targetSdkVersion 在 25
或以下的App,其Receiver不受影响,即使在Android8.0以上的机器上运行。
如果targetSdkVersion 在26或者以上,在Manifest注册的Receiver可能无法接收到广播消息,并且会在Logcat
里面打印出如下消息:
BroadcastQueue: Background execution not allowed: receiving Intent { act=com.xiaoqiang.try.something.receiver flg=0x2010 (has extras) } to xiaoqiang.com.trysomething/.broadcast.TheReceiver
有哪些影响
首先要了解一个概念。官方文档里提到implicit broadcast
,可译为隐式广播
,指那些没有指定接收App(即包名)的广播。
- 系统发送的广播毫无疑问都是隐式广播,因此基本上都会受到影响,除了部分受豁免广播之外
- App发送的自定义隐式广播,都会受到影响
为何限制隐式广播
总所周知,在Manifest
里面注册的系统广播接收器会被缓存在系统中,即使当App关闭之后,如果有相应的广播发出,应用程序仍然会被唤醒。比如如果有20个App在Manifest里面注册了ACTION_BOOT_COMPLETED
的广播接收器监听设备启动,那么当设备启动时,就会有20个应用程序被唤醒并作出相应的动作。而动态注册的广播则跟随组件的生命周期而消存。因此在Manifest里面注册广播接收器的App越多,设备的性能就越容易受到影响,限制隐式广播主要是为了优化系统性能。
如何应对这一限制
分析了受限制的原因之后,就知道该如何应对这一影响了。
- 优先使用动态注册Receiver的方式,能动态注册绝不使用Manifest注册
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.xiaoqiang.try.something.receiver");
TheReceiver receiver = new TheReceiver();
registerReceiver(receiver, intentFilter);
- 如果一定要Manifest注册,那么当发送广播的时候,指定广播接收者的包名,即发送显式广播
Intent intent = new Intent("com.xiaoqiang.try.something.receiver");
intent.putExtra("receive","test broadcast");
intent.setPackage(getPackageName());
//intent.setComponent(...)
sendBroadcast(intent);
- 如果要接收系统广播,而对应的广播在Android8.0中无法被接收,那么只能暂时把App的targetSdkVersion改为25或以下。
参考文章:
1. Android O and the Implicit Broadcast Ban
2. 官方文档