广播接受者是一个专注于接收广播通知消息,并可以做出对应处理的组件. 系统就会发出很多广播, 比如接收短信, 来电话, 电池电量低, 用户改变语言选项等, 都会发出广播通知用户. 应用程序也可以通过广播传递数据或者通知其他应用程序做出相应的处理. 一条广播可以有任意数量的广播接收者接收它. 所有的广播接收者都继承自BroadcastReceiver 类. 广播接受者没有用户界面, 但是可以启动一个activity或者NotificationManager 来响应它们接收到信息.
广播被分为两种: "普通广播(Normal broadcasts)" 和 "有序广播(Ordered broadcasts)".
普通广播是完全异步的,所有接受者可以同一时间没有顺序的情况下接收到, 消息传递的效率比较高. 但是接受者不能将接收到的结果传递给下一下并且不能终止广播.
有序广播是按照接受者声明的优先级别, 接受者依次接收广播 如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C 。优先级别声明在 intent-filter 元素的 android:priority 属性中,数越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置 。有序广播的接收者可以终止广播Intent的传播,广播Intent的传播一旦终止,后面的接收者就无法接收到广播。另外有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。
Context.sendBroadcast() 发送的是普通广播,所有订阅者都有机会获得并进行处理。
Context.sendOrderedBroadcast() 发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播(BroadcastReceiver.abortBroadcast()),如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将数据通过setResultExtras(Bundle)方法存放进结果对象,然后传给下一个接收者,下一个接收者通过代码:Bundle bundle = getResultExtras(true))可以获取上一个接收者存入在结果对象中的数据。
广播的生命周期是非常短的,当发送之后intent会到AndroidManifest.xml文件中找是不是有匹配的action,如果有就会调用Receiver ,然后获得Receiver 对象,再执行onReceive方法,这时候Receiver对象就没有用了,当我们再次点击按钮的时候就会重新获得对象,这就是BroadcastReceiver的生命周期.在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)的对话框.如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成.这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束,BroadcastReceiver就先结束了.BroadcastReceiver一旦结束,此时BroadcastReceiver的所在进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程).如果它的宿主进程被杀死,那么正在工作的子线程也会被杀死.所以采用子线程来解决是不可靠的.
两种广播的注册方法:
1.在应用程序的代码中进行注册
注册BroadcastReceiver
registerReceiver(receiver,filter);
取消注册BroadcastReceiver
unregisterReceiver(receiver);
2.在AndroidManifest.xml当中进行注册
<receiver android:name="SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
第一种注册的方法可以保证在应用程序安装之后,BroadcastReceiver始终处于活动状态,通常用于监听系统状态的改变,比如说手机的电量,wifi网卡的状态(当然,监视这些东西也是取决于软件的需求)。对于这样的BroadcastReceiver,通常是在产生某个特定的系统事件之后,进行相应的操作,比如说wifi网卡打开时,给用户一个提示;
第二种注册方法相对第一种要灵活的多,这样注册的BroadcastReceiver通常用于更新UI的状态。一般来说,都是在一个Activity启动的时候使用这样的方法注册BroadcastReceiver,一旦接收到广播的事件,就可以在onReceive方法当中更新当前的这个Activity当中的控件。但是需要注意的是如果这个Activity不可见了,就应该调用unregisterReceiver方法来解除注册
广播当中还有一种用法就是粘性广播(sendStickyBroadCast()), 它主要是为了解决在发送完广播之后,动态注册的接收者,也能够收到广播。举个例子首先发送一广播,我的接收者是通过程序中的某个按钮动态注册的。如果不是粘性广播,广播发出后再注册接受者肯定无法收到广播了。这是通过发送粘性广播就能够在动态注册接收者后也能收到广播。
发送粘性广播还需要发送粘性广播的权限:<uses-permission android:name="android.permission.BROADCAST_STICKY" />
//动态注册广播接收者
MyReceiver mr = new MyReceiver ();
IntentFilter filter = new IntentFilter();
filter.addAction("com.iteye.myreceiver.action ");
filter.addCategory(Intent.CATEGORY_DEFAULT);
Intent ii = this.registerReceiver(mr, filter);
String n = ii.getStringExtra("name");
Toast.makeText(this, "动态注册接收者完成,收到粘性广播,name=" + n, 1).show();
广播也可以控制接收方和发送方的权限:
1)如果广播发送方要求接收方必须有某个权限才能收到广播怎么做呢?
/**
* 发送广播,指定接收者权限
* sendBroadcast(i, "com.iteye.permission.receiver");//指定接收者权限
*/
public void sendBroadcast() {
//隐式意图,发送广播
Intent i = new Intent();
i.setAction("com.iteye.receiver.action");
i.putExtra("name", "tom");
this.sendBroadcast(i, " com.iteye.permission.receiver ");
Log.i("Other",".send ok!");
}
在清单文件里receiver必须有这个权限才能收到广播。
首先,需要定义权限:<permission android:name=" com.iteye.permission.receiver " />
然后,声明权限:<uses-permission android:name=" com.iteye.permission.receiver " />
这时接收者就能收到发送的广播。
2)反过来,如果接收者要求发送方必须拥有某个权限,我才接收你的广播怎么办呢?
<!-- 注册广播接收者
android:permission:控制发送方需要具备指定权限,才接收其广播.
-->
<receiver android:name=".MyReceiver" android:permission="com.permission.sender">
<intent-filter android:priority="100">
<action android:name="com.iteye.receiver.action" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
即使过滤器匹配,如果发送方没有相应权限,接收者也不会接收其广播。
注:这种方式好像发送方和接收方不在同一个应用程序中才有效, 如果在同一个应用程序中设置无效. 我的测试结果是这样的,也不知道是不是设置有误.