前言
BroadCastReceiver(广播接收者)作为四大组件,起到了在各组件中或不同进程中传递消息的功能,在Android中的广播主要由三部分组成:广播发送者,广播(需要传递的消息),广播接收者三部分组成。以下通过这三部分来介绍Android广播的相关知识。
定义
广播接收者是四大组件之一,是一个全局的监听器,能够接受APP内外发送的广播
应用场景
(1)各组件间的通信
(2)各个进程间的通信
(3)与系统之间的通信
Android广播实现原理
Android的广播的实现利用了观察者模式中的消息发布/订阅模型,首先广播接收者(消息订阅者)将自己注册到AMS(消息中心)上,当广播发送者(消息发布者)发送广播时,该广播首先会由AMS接收,AMS根据注册表中注册的信息选择出最为匹配的广播接收者(一个或多个),将广播发送个广播接收者的消息循环队列,通过消息循环调用广播接收者的onReceiver方法。

需要注意的是该过程是异步的,即广播发送者不关心是否有广播接收者进行接收,也不确定广播接收者何时接收能接收到广播。
广播发送者
广播发送者其实说白了就是在那个组件上调用的context. sendBroadcast(Intent intent)这个方法,谁就是广播发送者,这个很好理解
广播
广播发送者发送的广播其实就是一个Intent(意图),这个Intent携带者接收该广播所需要的条件和数据,广播主要有五大类型,分别是:
(1)普通广播:就是开发者所发送的广播
(2)系统广播:由Android系统发出的广播,例如开机和网络状态的改变
(3)有序广播:有序广播是指广播接收者按照一定的顺序来接收该广播,先接收该广播的广播接收者可以截断广播的发送。
(4)粘性广播:API21已经废止,不做说明
(5)APP内广播:在本APP范围内传播的广播
普通广播
普通广播的实例如下
Intent intent=new Intent();
intent.setAction("com.zhqy.receiver");
sendBroadcast(intent);
如果广播接收者能够匹配该action,便能够接收到该广播并回调onReceive()方法.
<receiver android:name="com.zhqy.myreceiver">
<intent-filter>
<action android:name="com.zhqy.receiver"></action>
</intent-filter>
</receiver>
如果该广播需要某种权限,则广播接收者也应该拥有某种权限
系统广播
系统广播是由系统基于某种特定情况发送的广播,系统常见的广播如下:
| 系统操作 | 说明 |
|---|---|
| 监听网络变化 | android.net.conn.CONNECTIVITY_CHANGE |
| 关闭或打开飞行模式 | Intent.ACTION_AIRPLANE_MODE_CHANGED |
| 充电时或电量发生变化 | Intent.ACTION_BATTERY_CHANGED |
| 电池电量低 | Intent.ACTION_BATTERY_LOW |
| 电池电量充足(即从电量低变化到饱满时会发出广播 | Intent.ACTION_BATTERY_OKAY |
| 系统启动完成后(仅广播一次) | Intent.ACTION_BOOT_COMPLETED |
| 按下照相时的拍照按键(硬件按键)时 | Intent.ACTION_CAMERA_BUTTON |
| 屏幕锁屏 | Intent.ACTION_CLOSE_SYSTEM_DIALOGS |
| 设备当前设置被改变时(界面语言、设备方向等) | Intent.ACTION_CONFIGURATION_CHANGED |
| 插入耳机时 | Intent.ACTION_HEADSET_PLUG |
| 未正确移除SD卡但已取出来时(正确移除方法:设置--SD卡和设备内存--卸载SD卡) | Intent.ACTION_MEDIA_BAD_REMOVAL |
| 插入外部储存装置(如SD卡) | Intent.ACTION_MEDIA_CHECKING |
| 成功安装APK | Intent.ACTION_PACKAGE_ADDED |
| 成功删除APK | Intent.ACTION_PACKAGE_REMOVED |
| 重启设备 | Intent.ACTION_REBOOT |
| 屏幕被关闭 | Intent.ACTION_SCREEN_OFF |
| 屏幕被打开 | Intent.ACTION_SCREEN_ON |
| 关闭系统时 | Intent.ACTION_SHUTDOWN |
| 重启设备 | Intent.ACTION_REBOOT |
如果要接收这些广播只需要在广播接收者的Intent-filter中添加对应的action即可。
有序广播
有序广播不是指广播的“有序”,而是指广播接收者的“有序”,广播接收的优先级由proority属性决定,数值越大,优先级越高,当数值相同时,动态注册的广播接收者拥有更高的优先级。有关动态注册的相关内容后面会讲到。
App内广播
App内的广播指的是发送的广播只能够在App内进行广播,其他App的广播接收者无法接收到该广播,保证了广播的安全性和高效率。App内的广播主要有两种方式进行广播的发送和接收:
1.将全局广播变为局部广播
(1)注册广播接收者时,exported的属性设置为false,该属性保证了不接受本APP以外的广播,但在广播发送和接收时应当增加permission,用于权限的验证。
(2) 发送广播时指定广播接收者所在的包名,此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。
通过intent.setPackage(packageName)指定包名
2.使用LocalManager来发送和接收广播
实例如下:
public class MainActivity extends AppCompatActivity {
private LocalBroadcastManager instance;
private MyReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取LocalBroadcastManager实例
instance = LocalBroadcastManager.getInstance(this);
receiver=new MyReceiver();
}
@Override
protected void onResume() {
super.onResume();
//动态注册广播接收者
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.zhqy.receiver");
instance.registerReceiver(receiver,intentFilter);
Intent intent=new Intent();
intent.setAction("com.zhqy.receiver");
//发送本地广播
instance.sendBroadcast(intent);
}
@Override
protected void onPause() {
super.onPause();
//解绑广播接收者
instance.unregisterReceiver(receiver);
}
}
需要注意的是广播的注册和发送均需要通过LocalBroadcastManager的实例进行,广播接收者采用动态注册的方式。本地广播接收者的注册于解绑放在onResume和onPause内,防止Activity意外销毁导致receiver没有及时回收造成内存泄漏
广播接收者
广播接收者是整个广播的重要组成部分,通过注册广播接收者接收对应的广播来实现消息的传播和对应功能的实现。广播接收者的注册主要有两种:静态注册和动态注册。
广播接收者的实现
不论是静态注册还是动态注册,广播接收者均应继承BroadcastReceiver,示例代码如下:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
当该广播接收者接收到广播后回调onReceive方法获取广播信息并进行相应的操作,需要注意的是广播接收者默认运行在UI线程中,不能再onReceive方法中做耗时操作。
静态注册
静态注册是指在manifest.xml中声明receiver,静态注册的receiver会在application初始化时动态生成广播接收者的实例来接收广播,即使app被关闭,该广播接收者仍能够接收匹配的广播并进行响应的处理。静态注册的相关属性如下:
exported:该广播接收者是否能够接收app外的广播,默认为true。
name:继承BroadcastReceiver子类的类名。
permission:具有相应permission的广播才能够被该广播接收者接收。
action:用于指定接收那种类型的广播,action可以指定一个或者多个
。
实例如下:
<receiver
//此广播接收者类是mBroadcastReceiver
android:name=".mBroadcastReceiver" >
//用于接收网络状态改变时发出的广播
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
动态注册
动态注册是指在组件中对广播接收者进行注册,需要在适时对广播接收者进行注册和解绑,预防内存泄漏的发生(广播接收者的解绑最好在onPause中进行),这是广播接收者只有在组件存在的且没有解绑的情况下接收广播。动态注册的示例如下:
public class MainActivity extends AppCompatActivity {
private MyReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
//创建IntentFilter
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.zhqy.receiver");
receiver=new MyReceiver();
//动态注册广播接收者
registerReceiver(receiver,intentFilter);
}
@Override
protected void onPause() {
super.onPause();
//解绑广播接受者
unregisterReceiver(receiver);
}
}
静态注册于动态注册的比较
静态注册的广播接收者会一直监听是否有广播的到来且不受组件声明周期的影响,如果需要一直监听是否有广播发送过来可以使用静态注册的方式,但该方式耗电量大且消耗系统资源较多。
动态注册比较灵活但受到组件生命周期的影响(注册和解除注册),当解除注册后将无法接收发送的广播。适合在特定时间接收广播的需求。
注意
在BroadcastReceiver子类的onReceive方法中获得的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;