一.概述
BroadcastReceiver作为四大组件之一,对发送出来的 Broadcast 进行过滤、接收和响应。
BroadcastReceiver没有实现图形用户界面,但是当它收到消息后,可以启动Activity,Service或者通过NotificationMananger提醒用户等等作为响应。
二.应用场景
1.不同组件之间通信(包括应用内 / 不同应用之间)。
2. 与 Android 系统在特定情况下的通信(比如当电话呼入时、网络可用时)。
3. 多线程通信。
三.BroadcastReceiver的分类
类别 | 定义 | 特点 | 注意 |
---|---|---|---|
普通广播(Normal Broadcast) | 发送一个广播,所有监听该广播的广播接收者都可以监听到该广播。 | 发送一个广播,所有监听该广播的广播接收者都可以监听到该广播。 | 如果发送广播有相应权限,那么广播接收者也需要相应权限 |
系统广播(System Broadcast) | Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播 | 当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播 | Android7.0以上应用不会接受和发送以下三种广播CONNECTIVITY_ACTION广播(网络状态改变);ACTION_NEW_PICTURE广播(一个新的相机,拍照和图片的添加);ACTION_NEW_VIDEO广播(一个新的视频摄像记录下来)->解决方案使用使用JobScheduler API |
有序广播(Ordered Broadcast) | 发送出去的广播被广播接收者按照先后顺序接收 | 先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播 | 广播顺序:按照Priority属性值(-1000到1000之间,值越大,优先级越高)从大到小排序,Priority属性相同者,动态注册的广播优先 |
App应用内广播(Local Broadcast) | App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。 | 相比于全局广播(普通广播),App应用内广播优势体现在安全性高和效率高 |
四.BroadcastReceiver的使用
BroadReceiver的使用可以分为三步:注册Receiver,发送广播,接收Receiver。
BroadcastReceiver的两种注册方式:
注册方式 | 定义 | 特点 |
---|---|---|
静态注册 | 在清单文件中为 BroadcastReceiver 进行注册 | a:不管该应用程序是否处于活动状态,都会进行监听,无需担忧广播接收器是否被关闭。b:会耗电,占内存。 |
动态注册 | 在程序中使用Context.registerReceiver注册 | a:在代码中进行注册后,当应用程序关闭后,就不再进行监听。b:在 Android 的广播机制中,动态注册的优先级是要高于静态注册优先级的。 |
1.静态注册:
在清单文件中为 BroadcastReceiver 进行注册,使用< receiver >标签声明,并在标签内用 < intent-filter > 标签设置过滤器。
普通广播:
(1)新建StaticReceiver.java,继承BroadcastReceiver,并实现onReceiver方法。
public class StaticReceiver extends BroadcastReceiver{
private static final String TAG = "StaticReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive: ");//收到消息进行处理
Intent intent1 = new Intent(context, SendActivity.class);
context.startActivity(intent1);
}
}
(2)清单文件中注册StaticReceiver:
<receiver android:name=".StaticReceiver">
<intent-filter>
<action android:name="com.liuwei.staticReceiver"/>
</intent-filter>
</receiver>
(3)使用sendBroadcast方法发送广播:
Intent intent = new Intent(); intent.setAction("com.liuwei.staticReceiver");
sendBroadcast(intent);
其中在清单文件中设置android:priority属性可以设置优先级,值越大,优先级越高,可以发送有序广播。
<receiver android:name=".StaticReceiver">
<intent-filter android:priority="98">
<action android:name="com.liuwei.staticReceiver"/>
</intent-filter>
</receiver>
有序广播:
(1)新建StaticReceiver1.java,StaticReceiver2.java,StaticReceiver3.java三个类,继承BroadcastReceiver并实现onReceiver方法。
<receiver android:name=".StaticReceiver1">
<intent-filter android:priority="99">
<action android:name="com.liuwei.staticOrderReceiver"/>
</intent-filter>
</receiver>
<receiver android:name=".StaticReceiver2">
<intent-filter android:priority="22">
<action android:name="com.liuwei.staticOrderReceiver"/>
</intent-filter>
</receiver>
<receiver android:name=".StaticReceiver3">
<intent-filter android:priority="66">
<action android:name="com.liuwei.staticOrderReceiver"/>
</intent-filter>
</receiver>
其中清单文件中设置android:priority表示优先级,值越大,优先级越高。
Intent intent = new Intent(); intent.setAction("com.liuwei.staticOrderReceiver");
sendOrderedBroadcast(intent, null);
(2)使用sendOrderedBroadcast(Intent intent,String receiverPermission);方法发送有序广播。
关于sendOrderedBroadcast方法中receiverPermission参数自定义权限的说明:
在清单文件中添加一个 < permission > 标签来声明自定义权限。
<permission
android:name="com.example.permission.receiver"
android:protectionLevel="signature" />
属性值 | 说明 |
---|---|
normal | 默认值。较低风险的权限,对其他应用,系统和用户来说风险最小。系统在安装应用时会自动批准授予应用该类型的权限,不要求用户明确批准(虽然用户在安装之前总是可以选择查看这些权限) |
dangerous | 较高风险的权限,请求该类型权限的应用程序会访问用户私有数据或对设备进行控制,从而可能对用户造成负面影响。因为这种类型的许可引入了潜在风险,所以系统可能不会自动将其授予请求的应用。例如,系统可以向用户显示由应用请求的任何危险许可,并且在继续之前需要确认,或者可以采取一些其他方法来避免用户自动允许。 |
signature | 只有在请求该权限的应用与声明权限的应用使用相同的证书签名时,系统才会授予权限。如果证书匹配,系统会自动授予权限而不通知用户或要求用户的明确批准 |
signatureOrSystem | 系统仅授予Android系统映像中与声明权限的应用使用相同的证书签名的应用。请避免使用此选项,“signature”级别足以满足大多数需求,“signatureOrSystem”权限用于某些特殊情况 |
测试:新建两个应用,sendapp,thirdapp。在两个app中分别新建StaticReceiver1.java,StaticReceiver2.java,StaticReceiver3.java三个类,继承BroadcastReceiver并实现onReceiver方法,在清单文件中注册Receiver,其中sendapp的清单文件中加入权限,thirdapp中未加入权限。
<uses-permission android:name="com.example.permission.receiver" />
结果:只有sendapp中可以收到消息,thirdapp中不能收到消息。
(3)拦截广播:
abortBroadcast();
2.动态注册:
动态注册是在代码中通过设置 IntentFilter对象实现的,不需要在清单文件中注册 Receiver 。
(1)注册Receiver:
BroadcastReceiver receiver = new DynamicReceiver();
IntentFilter intentFilter = new IntentFilter("com.liuwei.DynamicReceiver");
registerReceiver(receiver, intentFilter);
(2)发送广播:
Intent intent = new Intent(); intent.setAction("com.liuwei.DynamicReceiver");
sendBroadcast(intent);
(3)注销Receiver:
unregisterReceiver(receiver);
说明:
(1)对于动态广播,注册广播就必须注销广播,否则会导致内存泄露。
(2)动态广播最好在onResume()注册、onPause()注销。
因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露。
五.LocalBroadcastManager的使用
对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册。
api | 说明 |
---|---|
LocalBroadcastManager.getInstance(this).registerReceiver(BroadcastReceiver, IntentFilter) | 注册Receiver |
LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent) | 发送同步广播 |
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent) | 发送异步广播 |
LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver); | 注销Receiver |
1.注册Receiver:
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
LocalBroadcastManager localReceiver = new LocalReceiver();
IntentFilter intentFilter1 = new IntentFilter("com.liuwei.localManagerReceiver");
manager.registerReceiver(localReceiver, intentFilter1);
2.发送广播:
Intent intent = new Intent(); intent.setAction("com.liuwei.localManagerReceiver");
manager.sendBroadcast(intent);
3.注销Receiver:
manager.unregisterReceiver(localReceiver);
LocalBroadcastManager除了能解决BroadcastReceiver进程间安全性问题外,相对Context操作的BroadcastReceiver而言还具有更高的运行效率。
六.生命周期
BroadcastReceiver 的生命周期很短,在执行 onReceiver() 方法时才有效,一旦执行完毕,该Receiver 的生命周期就结束了。
所以onReceive必须在10秒钟内执行完毕,否则会产生ANR(Application Not Response)。如果需要进行耗时的操作,可以通过启动一个Service来实现。
注意:
对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的:
对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
对于应用内广播的动态注册(LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context。
对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;
以上测试代码请点击这里。
参考文档:
https://developer.android.google.cn/guide/components/broadcasts.html
http://www.jianshu.com/p/f348f6d7fe59
http://www.jianshu.com/p/ca3d87a4cdf3