解析BroadcastReceiver之你需要了解的一些东东
前些天把四大组件之一的Service扯了一遍,今天就要开始谈谈它的弟兄BroadcastReceiver了。写到这里我挺纠结的,因为广播接收者确实比较简单,但是各位就不要以为简单的就不内涵,也许我们慢慢探讨一下还能有另外一片天地。
惯例还是先会介绍一下基础的知识,后面会说说关于BroadcastReceiver的接收顺序还有其他的一些小知识。
BroadcastReceiver的概念
BroadcastReceiver的作用主要是用来监听系统或者应用发出的广播信息,然后根据广播信息作为相应的逻辑处理;说通俗点其实上就是一种全局监听器,要来实现系统中不同组件之间的通信。有时候也会用来作为传输少量而且发送频率低的数据,但是如果数据的发送频率比较高或者数量比较大就不建议用广播接收者来接收了,因为这样的效率很不好,因为BroadcastReceiver接收数据的开销还是比较大的。
BroadcastReceiver的基础使用
我们先来看看广播接收者的代码,如下:
1 public class MyBroadcastReceiver extends BroadcastReceiver { 2 @Override 3 public void onReceive(Context arg0, Intent arg1) { 4 // 用来实现广播接受者接收到广播后执行的代码逻辑 5 } 6 }
简单而完美,实现一个广播接受者仅仅需要我们重写一个函数onReceiver(),如果广播接受者接收到广播后将会执行该函数;但是这个前提是需要将这个广播接收者进行注册,一般来说,BroadcastReceiver的注册方式有且只有两种,一种是静态注册,另外一种是动态注册,广播接收者在注册后就开始监听系统或者应用之间发送的广播消息。
静态注册的方式:打开AndroidManifest清单文件中,像Activity、Service那种添加一个数据项进行注册,如下:
<receiver android:name=".MyBroadcastReceiver"> <intent-filter> <!-- action的命名规则一般建议为:包名.intent.类名 --> <action android:name="com.net168.testBcr.intent.mybroadcastreceiver"/> </intent-filter> </receiver>
静态注册的广播接收者就是一个常驻在系统中的全局监听器,也就是说如果你应用中配置了一个静态的BroadcastReceiver,而且你安装了应用而无论应用是否处于运行状态,广播接收者都是已经常驻在系统中了。但是有些人会很郁闷怎么销毁掉这个广播接收者,其实只要调用PackageManager将Receiver禁用就行了,简单实用吧?
动态注册的方式:使用registerReceiver(receiver, filter)进行广播接收者的注册,代码如下:
//filter是设置receiver的拦截器 IntentFilter filter = new IntentFilter("com.net168.testBcr.intent.mybroadcastreceiver"); MyBroadcastReceiver receiver = new MyBroadcastReceiver(); //动态注册广播接收者 registerReceiver(receiver, filter);
动态注册的广播接收者只有执行了registerReceiver(receiver, filter)才会开始监听广播消息,并对广播消息作为相应的处理。
销毁一个动态注册的BroadcastReceiver如下:
//撤销广播接受者的动态注册 unregisterReceiver(receiver);
撤销注册后广播接收者将不会再监听系统的广播消息。
静态注册的BroadcastReceiver和动态注册的BroadcastReceiver的一些区别
1、静态注册的广播接收者一经安装就常驻在系统之中,不需要重新启动唤醒接收者;动态注册的广播接收者随着应用的生命周期,由registerReceiver开始监听,由unregisterReceiver撤销监听,另外需要注意的一点就是如果应用退出后,没有撤销已经注册的接收者应用应用将会报错。
2、当广播接收者通过intent启动一个activity或者service时,如果intent中无法匹配到相应的组件。动态注册的广播接收者将会导致应用报错,而静态注册的广播接收者将不会有任何报错,因为自从应用安装完成后,广播接收者跟应用已经脱离了关系。
广播接收者机制
当系统或应用发出广播时,将会扫描系统中的所有广播接收者,通过action匹配将广播发送给相应的接收者,接收者收到广播后将会产生一个广播接收者的实例,执行其中的onReceiver()这个方法;特别需要注意的是这个实例的生命周期只有10秒,如果10秒内没执行结束onReceiver(),系统将会报错。另外在onReceiver()执行完毕之后,该实例将会被销毁,所以不要在onReceiver()中执行耗时操作,也不会在里面创建子线程处理业务(因为可能子线程没处理完,接收者就被回收了);正确的处理方法就是通过intent调用activity或者service处理业务。
发送广播
广播有三种类型:普通广播和有序广播,还有另外一种不怎么常用的粘性广播。
Android为了满足各种应用要求,设置了两个发送广播的方式,各有特点。一般普通广播可以应用在需要通知各个广播接收者的情况下如开机启动结束发送的广播;而有序广播则应用在需要有特定拦截的场景下如黑名单短信、电话拦截。
普通广播:普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,并且无法中断广播的传播。
Intent intent = new Intent(); intent.setAction("com.net168.testBcr.intent.mybroadcastreceiver"); intent.putExtra("data", "hello"); //发送普通广播 sendBroadcast(intent);
通过sendBroad(intent)来发送普通的广播消息。
有序广播:发送有序广播后,广播接收者将按预先声明的优先级依次接收Broadcast。优先级高的优先接收到广播,而在其onReceiver()执行过程中,广播不会传播到下一个接收者,此时当前的广播接收者可以终止广播继续向下传播,也可以将intent中的数据进行修改设置,然后将其传播到下一个广播接收者。
通过sendOrderedBroadcast()来发送有序广播。
//发送有序广播 sendOrderedBroadcast(intent, null);
对于有序广播接收者,我们可以再onReceiver中进行一些操作
public void onReceive(Context arg0, Intent intent) { //获取上一个广播的bundle数据 Bundle bundle = getResultExtras(true);//true:前一个广播没有结果时创建新的Bundle;false:不创建Bundle bundle.putString("key", "168168"); //将bundle数据放入广播中传给下一个广播接收者 setResultExtras(bundle); //终止广播传给下一个广播接收者 abortBroadcast(); }
在有序广播中,我们可以在前一个广播接收者将处理好的数据传送给后面的广播接收者,也可以调用abortBroadcast()来终结广播的传播。
粘性广播:该广播比较不常用,我们可以通过sendStickyBroadcast()来发送该类型的广播信息,这种的广播的最大特点是,当粘性广播发送后,最后的一个粘性广播会滞留在操作系统中。如果在粘性广播发送后的一段时间里,如果有新的符合广播的动态注册的广播接收者注册,将会收到这个广播消息,虽然这个广播是在广播接收者注册之前发送的,另外一点,对于静态注册的广播接收者来说,这个等同于普通广播。
广播接收者接收广播的次序
注意一点:广播接收者的优先级范围谷歌文档上标示的最大级为1000,但是实际上最大的级数是Integer.MAX(即2147483647)。
静态广播接收的处理器是由PackageManagerService负责,当手机启动或者新安装了应用的时候,PackageManagerService会扫描手机中所有已安装的APP应用,将AndroidManifest.xml中有关注册广播的信息解析出来,存储至一个全局静态变量当中。需要注意的是:
1、PackageManagerService扫描目录的顺序如下:
system/framework -> system/app -> vendor/app -> data/app -> drm/app-private
2、当处于同一目录下时:按照file.list()的返回顺序。(题外话:因为在data/app下的应用都是用户安装的,并且都是以com.xxx.xxx-1.apk 的形式出现,所以如果打算做手机管家之类的应用,需要好好的研究下包名,争取在file.list()的独木桥下抢的头筹---优先接收开机启动完成的广播。)
动态广播接收的处理器是由ActivityManagerService负责,当APP的服务或者进程起来之后,执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个另外的全局静态变量中。需要注意的是:
1、 这个并非是一成不变的,当程序被杀死之后,已注册的动态广播接收器也会被移出全局变量,直到下次程序启动,再进行动态广播的注册,当然这里面的顺序也已经变更了一次。
2、这里也并没完整的进行广播的排序,只记录的注册的先后顺序,并未有结合优先级的处理。
广播发出的时候,广播接收者接收的顺序如下:
如果广播为有序广播,那么会将动态广播处理器和静态广播处理器合并在一起处理广播的消息,最终确定广播接收的顺序: