赞
踩
0. 前言
BroadcastReceiver作为Android四大组件之一,像一个全局的监听器一样,是用来监听系统或者应用发出的广播信息,再在其onReceive()中执行相应的逻辑处理。
如可以监听系统的开机广播、电量较少的广播,也可以用来实现自己应用中不同组件之间的通信,如数据库中CURD后发送一个广播,并传递少量的数据,使某个Service中的变量发生改变。当然如果数据的发送量比较大就不建议使用广播接收者来接收了,因为BroadcastReceiver接收数据的开销还是比较大的。转载请注明出处为SEU_Calvin的博客。
1. BroadcastReceiver 的三种类型
1.1 普通广播
普通广播是完全异步的,而不是有所谓的接收顺序,消息传递的效率也比较高,并且无法中断广播的传播。
- Intent intent = new Intent();
- intent.setAction("com.seu.calvin.mybroadcastreceiver");
- intent.putExtra("data", "hello");
- sendBroadcast(intent);
1.2 有序广播
有序广播有所谓的优先级(谷歌文档上表示最大优先级为1000,但是实际上最大的级数是int最大值2147483647),优先级决定了接收顺序,在onReceiver()方法执行时,广播不会传播到下一个接收者,当前的广播接收者可以中断广播的传播,也可以将intent中的数据进行修改。
- //发送有序广播
- sendOrderedBroadcast(intent, null);
-
- //接收有序广播
- public void onReceive(Context arg0, Intent intent) {
- //参数为true表示前一个广播没有结果时创建新的Bundle;false表示不创建新的Bundle
- Bundle bundle = getResultExtras(true);
- bundle.putString("data", "hello again");
- setResultExtras(bundle);
- //终止广播传给下一个广播接收者
- //abortBroadcast();
- }
1.3 粘性广播
粘性广播已经被废弃,我们可以通过sendStickyBroadcast()来发送粘性广播。
当粘性广播发送后会滞留在操作系统中,如果有新的符合匹配规则的广播接收者动态注册了(在广播发送之后动态注册),也将会收到这个广播消息。而对于静态注册,效果等同于普通广播。
2. BroadcastReceiver 动静态注册的区别
(1)BroadcastReceiver在Manifest中静态注册后,应用一经安装,该广播接收者就常驻在系统中了(该广播接收者和应用可以认为已经脱离关系了),无论应用是否处于运行状态都可以接收对应的广播事件。
而动态注册的广播接收者由registerReceiver开始监听,由unregisterReceiver撤销监听,如果应用退出时没有撤销监听,应用将会报错。显然应用退出后,将不再接收对应的广播事件。
(2)如果广播接收者是静态注册的,通过intent启动一个activity/service时,若无法匹配不会报错,反之动态注册的话会报错。
(3)如果动静态注册使用的优先级都一样,那么动态注册的广播接收者优先级更高。
3. BroadcastReceiver 机制
3.1 广播接收者注册
3.1.1 静态注册
静态广播由PackageManagerService负责,当手机启动或者新安装了应用的时候,PackageManagerService会扫描手机中所有已安装的APP应用,将AndroidManifest.xml中有关注册广播的信息解析出来,存储至一个全局静态变量当中。
PackageManagerService扫描目录的顺序如下:system/framework、system/app、 vendor/app、data/app、drm/app-private,当处于同一目录下时按照file.list()的返回顺序。
因此当然是可以通过PackageManager取消静态注册的,取消后再次启动应用,静态注册就会失效。
3.1.2 动态注册
动态广播由ActivityManagerService负责,当代码执行到动态注册广播时进行加载(Binder通信),最后会存储在一个另外的全局静态变量中。
3.2 广播发送
广播发送时会通过Binder机制,分别和PackageManagerService以及ActivityManagerService进行广播的发送。后者再查找出符合匹配条件的广播接收者。
然后就是广播顺序,如果是普通广播:
(1)动态广播接收器优先于静态广播接收器;
(2)同优先级的静态广播接收器:先扫描到的大于后扫描到的;
(3)同优先级的动态广播接收器:先注册的大于后注册的。
如果是有序广播,会将动态广播处理器和静态广播处理器合并在一起处理广播,顺序如下:
(1)优先级高的先接收;
(2)同优先级,动态优先于静态;
(3)同优先级的静态广播接收器:先扫描到的大于后扫描到的;
(4)同优先级的动态广播接收器:先注册的大于后注册的。
3.3 广播接收者的处理
广播接收者拿到广播后产生一个广播接收者的实例并回调BroadcastReceiver中的onReceive()方法。
特别需要注意的是这个实例的生命周期只有10秒,如果10秒内没执行结束onReceiver(),系统将会报错。另外在onReceiver()执行完后,该实例将会被销毁,所以如果要处理耗时任务,不要在onReceiver()中直接创建子线程,而是通过intent调用service处理业务。
4. 拓展
静态注册的广播接收器即使app已经退出,依然可以接收到广播的说法,自Android 3.1开始有可能不再成立。
因为Android 3.1开始系统在Intent与广播相关的flag中增加了两个参数,分别是:
- intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);//包含已经停止的包
- intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);//不包含已经停止的包
即自Android3.1开始,系统广播自带FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。详情参考Android官方文档。
可以考虑使用将Service与App本身设置成不同的进程来在已退出app里接收广播。而自定义广播,自行为Intent添加flag参数即可。
转载请注明出处为:Android开发——BroadcastReceiver知识总结_SEU_Calvin的博客-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。