广播,是一个全局的监听器,属于Android四大组件之一,Android 广播分为两个角色:广播发送者、广播接收者
监听 / 接收 应用 App 发出的广播消息,并 做出响应
3.1)Android不同组件间的通信(含 :应用内 / 不同应用之间)
3.2)多线程通信
3.3)与 Android 系统在特定情况下的通信。如:电话呼入时、网络可用时
Android中的广播使用了设计模式中的观察者模式:基于消息的发布 / 订阅事件模型
Android将广播的发送者 和 接收者 解耦,使得系统方便集成,更易扩展
模型中有3个角色:
1、消息订阅者(广播接收者)
2、消息发布者(广播发布者)
3、消息中心(AMS,即Activity Manager Service)
观察者模式:
观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
继承BroadcastReceivre基类,必须复写抽象方法onReceive()方法
1.广播接收器接收到相应广播后,会自动回调 onReceive() 方法
2.一般情况下,onReceive方法会涉及 与 其他组件之间的交互,如发送Notification、启动Service等
3.默认情况下,广播接收器运行在 UI 线程,因此,onReceive()方法不能执行耗时操作,否则将导致ANR
// 继承BroadcastReceivre基类
public class mBroadcastReceiver extends BroadcastReceiver {
// 复写onReceive()方法
// 接收到广播后,则自动调用该方法
@Override
public void onReceive(Context context, Intent intent) {
//写入接收广播后的操作
}
}
如下为监听网络状态变化的广播接收器
class NetworkChangeReceiver extends BroadcastReceiver{//广播接收器类
@Override
public void onReceiver(Context context,Intent intent){
//这里需要权限,需要在AndroidManifest.xml中进行网络访问权限申请:
//
ConnectivityManager connectionManager = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isAvailable()) {
//有网
Toast.makeText(context, "network is available",Toast.LENGTH_SHORT).show();
} else {
//无网
Toast.makeText(context, "network is unavailable",
Toast.LENGTH_SHORT).show();
}
}
}
注册的方式分为两种:静态注册、动态注册
使用:在AndroidManifest.xml里通过标签声明
特点:常驻、不受任何组件的生命周期影响(应用程序关闭后,如果有信息广播,程序依旧会被系统调用),耗电,占内存
应用场景:需要时刻监听广播
//用于指定此广播接收器将接收的广播类型
// IntentFilter翻译成中文就是“意图过滤器”,主要用来过滤隐式意图。当用户进行一项操作的时候,Android系统会根据配置的 “意图过滤器” 来寻找可以响应该操作的组件,服务。
//本示例中给出的是用于接收网络状态改变时发出的广播
当此 App首次启动时,系统会自动实例化mBroadcastReceiver类,并注册到系统中。
使用:在代码中调用Context.registerReceiver()方法
特点:非常驻、灵活、跟随组件的生命周期变化(组件结束,广播结束。故在组件结束前,必须移除广播接收器)
应用场景
2.1)源码
// 选择在Activity生命周期方法中的onResume()中注册
@Override
protected void onResume(){
super.onResume();
// 1. 实例化BroadcastReceiver子类 & IntentFilter(意图过滤器,接受广播类型)
mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
// 2. 设置接收广播的类型(网络变化广播)
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
// 3. 动态注册:调用Context的registerReceiver()方法
registerReceiver(mBroadcastReceiver, intentFilter);
}
// 注册广播后,要在相应位置记得销毁广播
// 即在onPause() 中unregisterReceiver(mBroadcastReceiver)
// 当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中
// 当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。
@Override
protected void onPause() {
super.onPause();
//销毁在onResume()方法中的广播
unregisterReceiver(mBroadcastReceiver);
}
}
2.2)动态广播最好在Activity 的 onResume()注册、onPause()注销。
广播 是 用”意图(Intent)“标识,定义广播的本质 = 定义广播所具备的“意图(Intent)”
广播发送 = 广播发送者 将此广播的“意图(Intent)”通过sendBroadcast()方法发送出去
开发者自身定义 intent的广播(最常用)。
1、发送者发送自定义广播
Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action
intent.setAction(BROADCAST_ACTION);
//发送广播
sendBroadcast(intent);
2、接受者注册广播
//用于接收网络状态改变时发出的广播
若被注册了的广播接收者中注册时intentFilter的action与上述匹配,则会接收此广播(即进行回调onReceive())。
Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播
每个广播都有特定的Intent - Filter(包括具体的action),Android系统广播action如下:(部分)
系统操作 Action
监听网络变化 android.net.conn.CONNECTIVITY_CHANGE
电池电量低 Intent.ACTION_BATTERY_LOW
屏幕锁屏 Intent.ACTION_CLOSE_SYSTEM_DIALOGS
屏幕被关闭 Intent.ACTION_SCREEN_OFF
屏幕被打开 Intent.ACTION_SCREEN_ON
注:当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播
发送出去的广播被广播接收者按照先后顺序接收(按照Priority属性值从大-小排序)
sendOrderedBroadcast(intent);
有序广播与无序广播区别:
Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认值为true),App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。
(1)将全局广播设置为局部广播
(a)注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;
(b)在广播发送和接收时,增设相应权限permission,用于权限验证;
(c)发送广播时指定该广播接收器所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。(通过intent.setPackage(packageName)指定报名)
(2) 使用封装好的LocalBroadcastManager类
使用方式上与全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将参数的context变成了LocalBroadcastManager的单一实例
//注册应用内广播接收器
//步骤1:实例化BroadcastReceiver子类 & IntentFilter mBroadcastReceiver
mBroadcastReceiver = new mBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
//步骤2:实例化LocalBroadcastManager的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//步骤3:设置接收广播的类型
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
//步骤4:调用LocalBroadcastManager单一实例的registerReceiver()方法进行动态注册
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
//取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
//发送应用内广播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);
注:对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的
(3) 本地广播与全局广播的差别
(3.1)定义
全局广播BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通信的一种方式
本地广播LocalBroadcastReceiver仅在自己的应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全广播只在这个程序里,而且效率更高。
(3.2)使用
全局广播:
1)制作intent(可以携带参数)
2)使用sendBroadcast()传入intent;
3)制作广播接收器类继承BroadcastReceiver重写onReceive方法(或者可以匿名内部类啥的)
4)在java中(动态注册)或者直接在Manifest中注册广播接收器(静态注册)使用registerReceiver()传入接收器和intentFilter
5)取消注册可以在OnDestroy()函数中,unregisterReceiver()传入接收器
本地广播:
1)LocalBroadcastReceiver不能静态注册,只能采用动态注册的方式。
2)在发送和注册的时候采用,LocalBroadcastManager的sendBroadcast方法和registerReceiver方法
(1)构造函数
public static LocalBroadcastManager getInstance(Context context) {
synchronized (mLock) {
if (mInstance == null) {
mInstance = new LocalBroadcastManager(context.getApplicationContext());
}
return mInstance;
}
}
private LocalBroadcastManager(Context context) {
mAppContext = context;
mHandler = new Handler(context.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_EXEC_PENDING_BROADCASTS:
executePendingBroadcasts();
break;
default:
super.handleMessage(msg);
}
}
};
}
先看构造函数,单例实现因而私有化构造函数。
注意的是基于主线程的 Looper 新建了一个 Handler,handleMessage中会调用接收器对广播的消息进行处理,也是 LocalBroadcastManager 的核心部分,具体见后面executePendingBroadcasts()介绍。
(2)注册接收器
HashMap> mReceivers
= new HashMap>();
HashMap> mActions
= new HashMap>();
public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
synchronized (mReceivers) {
ReceiverRecord entry = new ReceiverRecord(filter, receiver);
ArrayList filters = mReceivers.get(receiver);
if (filters == null) {
filters = new ArrayList(1);
mReceivers.put(receiver, filters);
}
filters.add(filter);
for (int i=0; i entries = mActions.get(action);
if (entries == null) {
entries = new ArrayList(1);
mActions.put(action, entries);
}
entries.add(entry);
}
}
}
mReceivers 存储广播和过滤器信息,以BroadcastReceiver作为 key,IntentFilter链表作为 value。mReceivers 是接收器和IntentFilter的对应表,主要作用是方便在unregisterReceiver(…)取消注册,同时作为对象锁限制注册接收器、发送广播、取消接收器注册等几个过程的并发访问。
mActions 以Action为 key,注册这个Action的BroadcastReceiver链表为 value。mActions 的主要作用是方便在广播发送后快速得到可以接收它的BroadcastReceiver。
(3)发送广播
public boolean sendBroadcast(Intent intent) {
synchronized (mReceivers) {
final String action = intent.getAction();
final String type = intent.resolveTypeIfNeeded(mAppContext.getContentResolver());
final Uri data = intent.getData();
final String scheme = intent.getScheme();
final Set categories = intent.getCategories();
……
ArrayList entries = mActions.get(intent.getAction());
if (entries != null) {
if (debug) Log.v(TAG, "Action list: " + entries);
ArrayList receivers = null;
for (int i=0; i= 0) {
if (debug) Log.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(receiver);
receiver.broadcasting = true;
} else {
……
}
}
if (receivers != null) {
for (int i=0; i
先根据Action从mActions中取出ReceiverRecord列表,循环每个ReceiverRecord判断 filter 和 intent 中的 action、type、scheme、data、categoried 是否 match(intentFilter的match机制),是的话则保存到receivers列表中,发送 what 为MSG_EXEC_PENDING_BROADCASTS的消息,通过 Handler 去处理。
(4)消息处理
Java
private void executePendingBroadcasts() {
while (true) {
BroadcastRecord[] brs = null;
synchronized (mReceivers) {
final int N = mPendingBroadcasts.size();
if (N <= 0) {
return;
}
brs = new BroadcastRecord[N];
mPendingBroadcasts.toArray(brs);
mPendingBroadcasts.clear();
}
for (int i=0; i
以上为消息处理的函数。mPendingBroadcasts转换为数组BroadcastRecord,循环每个receiver,调用其onReceive函数,这样便完成了广播的核心逻辑。
(5)取消注册
public void unregisterReceiver(BroadcastReceiver receiver) {
synchronized (mReceivers) {
ArrayList filters = mReceivers.remove(receiver);
if (filters == null) {
return;
}
for (int i=0; i receivers = mActions.get(action);
if (receivers != null) {
for (int k=0; k
从mReceivers及mActions中移除相应元素。
(1) LocalBroadcastManager 的核心实现实际还是 Handler,只是利用到了 IntentFilter 的 match 功能,至于 BroadcastReceiver 换成其他接口也无所谓,顺便利用了现成的类和概念而已。
(2) 因为是 Handler 实现的应用内的通信,自然安全性更好,效率更高。
本地广播发送的广播只在自身app传播。不必担心隐私数据泄露。
其他app无法对该app发送广播。不必担心安全漏洞的利用。
本地广播更加高效、安全。
LocalBroadcast内部协作主要是靠两个Map集合:mReceivers和mActions,当然还有一个List集合mPendingBroadcasts,这个主要存储待接收的广播对象。
(1)自定义BroadcastReceiver子类LocalBroadcastReceiver
public class LocalBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
localMsg.setText(intent.getStringExtra(MSG_KEY));
}
}
(2)注册接收器
LocalBroadcastReceiver localReceiver = new LocalBroadcastReceiver();
LocalBroadcastManager.getInstance(context).registerReceiver(localReceiver, new IntentFilter(ACTION_LOCAL_SEND));
(3)发送广播
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(ACTION_LOCAL_SEND));
(4)取消注册
LocalBroadcastManager.getInstance(context).unregisterReceiver(localReceiver);