Android中的广播,即BroadcastReceiver,是应用开发中四大组件之一,通过发送/接收广播,可以实现不同组件的通信。

广播的分类

根据是否跨进程,可分为全局广播和本地广播。
全局广播:广播可以发送给不同进程,可以接收不同进程广播消息

本地广播:
使用LocalBroadcastManager.getInstance(context).sendBroadcast发送本地广播
使用本地广播相比全局广播有如下优势:
1.保护隐私: 广播的数据不会离开当前进程,不用担心数据会泄露;
2.安全: 其他应用不可能发送该广播给当前进程, 因此不用担心安全漏洞;
3.效率: 与全局广播在整个系统传播相比,本地广播效率更高;


根据广播接收顺序,可分为两类:
1.普通广播
- 通过Context.sendBroadcast发送
- 广播是以异步方式发送
- 广播的接收者运行顺序不确定
- 广播接收者不能使用彼此之间的结果,不能放弃广播

手持安卓广播接收RFID读取结果 安卓广播接收器_广播接收器


2.有序广播
- 通过Context.sendOrderedBroadcast发送
- 一次发送给一个接收者,接收者按顺序进行
- 当前广播接收者可以传递结果给下一个接收者
- 当前广播接收者可以放弃广播,则它后面的广播接收都将收不到该广播
- 可以通过设置android:priority属性控制广播接收的顺序,如果优先级相同则顺序不确定

手持安卓广播接收RFID读取结果 安卓广播接收器_android_02



普通广播又有:
1.粘性广播
- 可通过Context.sendStickyBroadcast发送粘性广播。
- 粘性广播发送的是消息是粘性的(sticky),Receiver如果在接收粘性广播前被销毁,那么下次重新创建时会再次接收到该广播。
- 发送粘性广播需要权限 android.permission.BROADCAST_STICKY
- 在onReceive中接收粘性广播:
 if(isInitialStickyBroadcast){
//接收粘性消息
 }else{
//接收新消息
 }

2.定向广播
给指定的应用发送广播
Intent intent = new Intent(action);
intent.setComponent(new ComponentName(packageName,className));
sendBroadcast(intent);

安全问题

(1)Intent的命名空间是全局的。确保广播的Intent action只适用于你自己的命名空间中,否则可能和其他应用冲突。


(2)当使用registerReceiver(BroadcastReceiver, IntentFilter)注册广播接收者时,任何应用都有可能发送广播给该接收者。可以添加权限来控制谁可以给它发广播。


(3)在应用的manifest指定广播接收者并且指定intent-filters时,任何其他应用都可以给它发送广播而不管这个filter。为阻止其他应用给它发送广播,可使用android:exported="false"


(4)当使用sendBroadcast(Intent)或相关API时,一般情况任意其他应用都有可能收到广播。可以通过设置权限来控制谁可以接收该广播。从ICS开始,可以通过使用Intent.setPackage限制广播只发给单个应用。


所有以上问题在LocalBroadcastManager中都没有,因为广播的intent不会超出当前进程。



发送广播时强加权限,可以通过给sendBroadcast(Intent, String)或sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)


传递非空的权限参数来完成。只有拥有相应权限(在AndroidManifest.xml中使用<uses-permission>申请权限)的广播接收者才能收到发送的广播。



接收广播时强加权限,可以通过在注册广播时提供非空权限参数来完成(静态或动态注册都可以)。


只有拥有相应权限(在AndroidManifest.xml中使用<uses-permission>申请权限)的广播发送者才能给该接收者发送广播。


广播生命周期

一个BroadcastReceiver对象只在onReceive(Context, Intent)方法执行期间有效,一旦该方法返回,系统认为该对象已经结束,不再处于活动状态。


实现onReceive(Context, Intent) 方法时应注意,不要使用异步的操作,因为你需要在方法结束后调用异步处理程序,但那个时候广播接收器已经不处于活动状态,系统随时可以在异步操作完成之前杀掉进程。


特别是不要在广播接收器中显示对话框或绑定服务。对于前者,应使用NotificationManager API来代替,对于后者,可以使用Context.startService()启动服务。

onReceive方法运行在主线程(UI线程),因此不要做耗时操作,否则执行时间超过10s 会造成ANR现象。

当前运行广播(即当前执行广播接收器onReceive方法)的进程会被系统认为是前台进程,除非是内存极度不够的情况,否则系统不会杀掉该进程。
一旦onReceive方法返回,广播接收器不是活动状态,它的宿主进程的重要程度只和任何其他运行的应用组件一样。这点特别重要,因为假如进程只运行广播接收器,那么onReceive方法返回后系统认为该进程是空进程,从而容易杀掉它以便给其他更重要的进程提供更多资源。
这意味着对于长时间的操作,应该使用service,结合广播接收器以使整个操作期间进程处于活跃状态。