背景:两个应用需要通信,和同事讨论了一下,因为功能比较简单所以打算使用广播进行通信。写完后发现在android O上静态注册的receiver无法接收到广播。顺便就研究一下有什么方法可以解决这个问题。
代码:
举例说明,最简单的发送广播代码:
Intent intent = new Intent("com.test.broadcast.receiver");
this.sendBroadcast(intent);
接收端:
package com.example.h284333.myapplication.receiver;
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Log.d("gsy","app onreceiver ="+intent.getAction());
}
}
在AndroidManifest中注册
运行后发现log没有打印出来,检查所有log发现。
BroadcastQueue: Background execution not allowed: receiving Intent { act=com.test.broadcast.receiver flg=0x10 } to com.example.h284333.myapplication/.receiver.MyReceiver
谷歌开发者网站中关于android O的说明中找到这么一段描述:
In addition, to improve device performance, the system limits certain behaviors by apps that are not running in the foreground. Specifically:
Apps cannot use their manifests to register for most implicit broadcasts (that is, broadcasts that are not targeted specifically at the app).
大概意思就是为了提高设备性能,系统限制了不在前台运行app的某些功能:
App不能使用在manifests中注册receiver的方式接收大部分的隐式广播。
为什么不是所有的隐式广播,因为有的系统的广播还是可以用静态注册方式接收的,比如开机广播,安装apk的广播。
所以只能够指定报名发送广播了,修改发送广播的代码:
ComponentName componentName = new ComponentName("com.example.h284333.myapplication","com.example.h284333.myapplication.receiver.MyReceiver");
Intent intent = new Intent("com.test.broadcast.receiver");
intent.setComponent(componentName);
sendBroadcast(intent);
需要注意的是componentName中指定的是你的接收器,第一个参数是接收器所在应用的包名,而不是接收器的包名。以上面的例子说明,接收器的包名是com.example.h284333.myapplication.receiver。应用的包名是com.example.h284333.myapplication。所以第一个参数应该写com.example.h284333.myapplication。第二个参数就是receiver的class名了。
运行后成功接收到广播:
08-12 01:11:44.213 12932 12932 D gsy : app onreceiver =com.test.broadcast.receiver
但是总感觉这样就不像是一个广播,更像是一个点对点的跨进程通信方式。如果有不止一个的广播接收器总不能一一指定componentName吧。方法总是有的,
PackageManager有一个queryBroadcastReceivers方法,可以检索出指定intent的receiver。
public abstract List queryBroadcastReceivers (Intent intent, int flags)
Retrieve all receivers that can handle a broadcast of the given intent.
有了这个方法我们就可以给所有的receiver发送广播了,代码如下:
private void sendHXBroadCast() {
Intent logIntent = new Intent();
logIntent.setAction("com.test.broadcast.receiver");
PackageManager pm=this.getPackageManager();
List matches=pm.queryBroadcastReceivers(logIntent, 0);
if(matches != null && matches.size() >= 1){
for (ResolveInfo resolveInfo : matches) {
Intent intent=new Intent(logIntent);
ComponentName cn=new ComponentName(
resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);
intent.setComponent(cn);
this.sendBroadcast(intent);
}
}
}
如此便完美解决了android O 静态注册的广播接收问题了。