Android的BroadcastReceiver组件
BroadcastReceiver的作用:
BroadcastReceiver,是和Intent有很大关系的Android组件。
Android中的 Intent 可以用来:
1. 在应用程序内部和应用程序之间传递数据(传输信息的机制),以及通过监听Intent来检测到系统状态的变化;
2. 启动Activity和Service;
3. Broadcast Intent用来在系统范围内公布应用程序事件。
Broadcast Intent用于在系统范围内广播应用程序事件,而BroadcastReceiver则用于接收或监听Intent事件,对发出的Broadcast进行过滤、接受并响应的一类组件(发送通知,更新UI或者数据,应用程序间相互通信,监听系统状态;比如开机,网络等)。上述两者的作用,恰好是相反的。
在Android系统中,广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能;当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作;当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。
BroadcastReceiver包括两个概念,广播发送者和广播接收者(Receiver),这里的广播实际就是指Intent;应用程序可以自己发送广播自己接收,也可以接受系统或其他应用的广播或是发送广播给其他应用程序。当发送者发送某个广播时,系统会将发送的广播(Intent)与系统中所有注册的符合条件的接收者(Receiver) 的IntentFilter进行匹配。若匹配成功,则执行相应接收者的onReceive(),匹配规则见Intent和IntentFilter的匹配规则。
“Android中的广播机制设计的非常出色,很多事情原本需要开发者亲自操作的,现在只需等待广播告知自己就可以了,大大减少了开发的工作量和开发周期。”
BroadcastReceiver的使用方法:
要使用Broadcast Receiver能够接收广播,就需要对其进行注册,既可以使用代码,也可以在应用程序的manifest文件中注册(此时称为manifest接收器)。无论怎么注册,都需要使用一个Intent Filter来指定要监听哪些Intent(特指:Intent的Action)和数据。
对于包含manifest接收器的应用程序,在Intent被广播出去的时候,应用程序不一定非要处于运行状态才能执行接收(而对于在代码中注册的接收器只会在包含它的应用程序组件运行时才会响应Broadcast Intent)。当匹配的Intent被广播出去的时候,它们会被自动地启动。
对于资源管理来说,这一点是非常优秀的,因为它提供了一种能够创建出事件驱动型的应用程序机制(不仅可以接受应用程序自定义的广播,还可以接受系统级别的广播)。即使应用程序被关闭或者销毁了,也仍然能够对广播事件作出响应。
1. 静态注册广播接受者
public class DemoBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Log.d(Constanst.TAG, "DemoBroadcastReceiver::"+msg);
}
}
对应的要到AndroidManifest.xml文件中进行注册:
<receiver android:name=".DemoBroadcastReceiver">
<intent-filter>
<action android:name="com.androidiot.demo.DEMO.TEST"></action>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
2. 动态注册广播
@Override
protected void onStart() {
super.onStart();
// TODO 此处注册广播监听
receiver = new MyBroadReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Constanst.ACTION);
MainActivity.this.registerReceiver(receiver, filter);
}
此处是在Activity中的onStart()中注册广播,与此对应的,需要在onPause()中取消广播监听:
@Override
protected void onPause() {
super.onPause();
// TODO 此处取消广播监听
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
}
对于自己发送和接受的广播可以通过registerReceiver注册,对于系统常用广播的接收通常用<receiver>标签注册。registerReceiver可以手动控制,所以适当的注册和取消注册能节省系统资源,<receiver>标签系统开机后一直有效。
BroadcastReceiver在onReceive()执行结束后即表示生命周期结束,所以不适合在onReceive中做绑定服务操作;结束后若某个进程只含有该BroadcastReceiver,则优先级将降低可能被系统回收,所以BroadcastReceiver中不适合做一些异步操作,如新建线程下载数据,BroadcastReceiver结束后可能在异步操作完成前进程已经被系统kill。同时由于ANR限制BroadcastReceiver的onReceive()必须在5秒内完成,而且onReceive()默认会在主线程中执行,所以BroadcastReceiver中不适合做一些耗时操作,对于耗时操作需要交给service处理,比如网络或数据库耗时操作、对话框的显示(因为现实时间可能超时,用Notification代替)。
BroadcastReceiver的类型:
Android中的广播类型分为两种:无序广播和有序广播;前者为异步的,也就是大致实现了同一时间接收到广播,不分先后顺序;后者根据接受者的优先级别,实现广播的先后接受。
无序广播的各个接受者,无法做到停止广播的传递;有序广播中,优先接收到广播的接受者可以实现终止广播的传递(并且可以改变传递的Extras的内容)。
BroadcastReceiver的使用注意事项:
对于接收到指定广播的onReceive(),必须在5s内执行完毕;否则会出现ANR。
一般情况下,Broadcast Receiver将会更新内容、启动Servicee、更新UI,或者使用Notification Manager来通知用户。5秒的执行限制保证了主要的处理工作不能够、也不应该由Broadcast Receiver直接完成。
BroadcastReceiver的设计初衷就是从全局考虑的,可以方便应用程序和系统、应用程序之间、应用程序内的通信,所以对单个应用程序而言BroadcastReceiver是存在安全性问题的,相应问题及解决如下:
a、当应用程序发送某个广播时系统会将发送的Intent与系统中所有注册的BroadcastReceiver的IntentFilter进行匹配,若匹配成功则执行相应的onReceive函数。可以通过类似sendBroadcast(Intent, String)的接口在发送广播时指定接收者必须具备的permission。或通过Intent.setPackage设置广播仅对某个程序有效。
b. 当应用程序注册了某个广播时,即便设置了IntentFilter还是会接收到来自其他应用程序的广播进行匹配判断。对于动态注册的广播可以通过类似registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)的接口指定发送者必须具备的permission,对于静态注册的广播可以通过android:exported="false"属性表示接收者对外部应用程序不可用,即不接受来自外部的广播。
c.上面两个问题其实都可以通过LocalBroadcastManager来解决,LocalBroadcastManager只会将广播限定在当前应用程序中。LocalBroadcastManager局部广播管理器,包含在Android Support Library中,局部广播的作用域要小,使用局部广播管理器比发送全局广播更加有效,也确保了应用程序外部的任何组件都收不到广播的Intent,不会有私人数据或敏感数据泄露出去。类似的,其他的应用程序也不能向你的接收器发送广播,避免了这些接收器成为安全漏洞。