广播
MoMo Lv5
  • Android里广播的分类
  • 程序A能否接收到程序B的广播
  • 广播注册的方式,并简单描述其区别

Broadcast的定义

Broadcast Receiver是Android四大组件之一,是全局大喇叭,就像以前学校里面的大喇叭一样,有什么事情,就通过广播通知到全校师生。Android的广播机制是一种广泛运用的在应用程序之间传输信息的机制。主要有两大角色:广播接收者和广播发送者。因此,我们可以注册一个广播接收者,用来接收其他进程或者系统发出的广播;同样的,我们也可以通过广播发送者,向其他进程发送我们的广播,告诉其他进程需要做某个动作。

Broadcast的注册方式

通过了解Broadcast的注册方式,是了解BroadcastReceiver的用法是最直接有效的,有静态注册和动态注册两种方法。

静态注册

在AndroidManifest.xml清单文件里直接声明的方式叫做静态注册。

1
2
3
4
5
6
7
8
<receiver 
//此广播接收者类是mXRReceiver
android:name=".mXRReceiver" >
//用于系统启动完成时,接收系统发送的广播
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

同时附上其他receiver的属性说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<receiver
android:enabled=["true" | "false"]
//此broadcastReceiver能否接收其他App的发出的广播
//默认值是由receiver中有无intent-filter决定的如果有intent-filter默认值为true否则为false
android:exported=["true" | "false"]
android:icon="drawable resource"
android:label="string resource"
//继承BroadcastReceiver子类的类名
android:name=".mXRReceiver"
//具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收
android:permission="string"
//BroadcastReceiver运行所处的进程
//默认为app的进程可以指定独立的进程
//Android四大基本组件都可以通过此属性指定自己的独立进程
android:process="string" >

//用于指定此广播接收器将接收的广播类型
//本示例中给出的是用于系统启动完成时,接收系统发送的广播
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

然后重新onReceive()函数。

1
2
3
4
5
6
7
8
public class mXRReceiver extends BroadcastReceiver {

//接收到广播后自动调用该方法
@Override
public void onReceive(Context context, Intent intent) {
//写入接收广播后的操作
}
}

如上面代码,此时注册了mXRReceiver这个广播,当系统启动后,就会发送BOOT_COMPLETED的广播,符合mXRReceiver所设置的过滤条件,就会自动调用onReceive()函数,执行对应内容。

注意:onReceive()函数不能执行耗时流程。

动态注册

所谓动态注册,就是代码运行到了才注册广播。具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void initBroadcastReceiver() {
if (mXRBroadcastReceiver == null) {
mXRBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
...
}
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.BOOT_COMPLETE);
registerReceiver(mXRBroadcastReceiver, intentFilter);
}
}

动态广播最好在Activity的onResume()注册、onPause()注销。一旦忘记注销,那么就会造成内存泄露哦。

静态/动态注册的区别

  • 静态注册不受app是否运行所影响,即使app没有运行,app里静态注册的广播接收者也可以接收广播,因此比较耗电,占内存。适合长时间监听广播,如系统广播。
  • 动态注册的广播在组件结束之前,也会随之结束(当然是手动注销的),适合只在特殊时刻监听广播。
  • 动态注册的优先级高于静态广播。

Broadcast的分类

广播主要分为以下5个类型:

  • 普通广播(Normal Broadcast)
  • 系统广播(System Broadcast)
  • 有序广播(Ordered Broadcast)
  • 粘性广播(Sticky Broadcast)
  • 本地广播(Local Broadcast)

普通广播

也就是标准广播,是一种完全异步执行的广播,和学校大喇叭完全一样,发出广播后,所有广播接收者都能收到广播,且没有优先之分,上面程序都是普通广播。

系统广播

可以理解为安卓源码里面已经存在的广播,一般只要涉及系统基础操作的,都会有对应的系统广播,现列举如下:

监听网络变化 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

有序广播

有序广播是一种同步执行的广播,按广播接收者的优先级由高到低排序,轮流接收到广播,且前面的广播接收者可以拦截该广播,这样后面的广播接收者就无法接收到该广播了。同时,前面的广播接受者也可以修改该广播并不做拦截,这样下一个接收到的广播就是被修改过的。 设置广播接收者的优先级可以用priority属性,数字越高代表优先级越高,最高是1000.

1
2
3
4
5
6
7
8
<receiver 
//此广播接收者类是mXRReceiver
android:name=".mXRReceiver" >
//用于系统启动完成时,接收系统发送的广播
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

使用起来,和普通广播仅差别在发送函数。普通广播sendBroadcast(intent),有序广播使用 sendOrderedBroadcast(intent);

本地广播

BroadcastReceiver可用于不同应用之间传递消息,但难免会出现这两种情况:

  • 我们的App注册了广播接收者A,同时其他App可能要完成某个操作,碰巧发送了符合接收者A过滤条件的广播,导致我们的App就一直错误的接收到了这个广播;
  • 我们的App注册了广播接收者A,同时其他App也碰巧注册了和我们同样过滤条件的广播接收者,这样就导致本来是我们App接收的广播,其他App也接收到了;

基于这两大问题,LocalBroadcastManager就可以很好的解决该问题。LocalBroadcastManager用于应用内部传递消息,比broadcastReceiver更加高效和安全

为何更加高效安全

BroadcastReceiver是以 Binder 通讯方式为底层实现的机制不同,众所周知Binder是跨进程的。而LocalBroadcastManager 是利用应用内部的Handler来实现,只是利用到了 IntentFilter 的 match 功能,因为是 Handler 实现的应用内的通信,自然安全性更好,效率更高。

如何实现本地广播

  1. 把全局广播改为本地广播
    1. 注册广播时将exported属性设置为false,表示该广播接收者不对外;
    2. 在广播发送和接收时,增设相应权限permission,用于权限验证;
    3. 发送广播时通过intent.setPackage(packageName)指定该广播接收器所在的包名,因此保证该发送出去的广播只会发送到指定包名的App内的广播接收者。
  2. 使用LocalBroadcastManager类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//注册应用内广播接收器
//步骤1:实例化自定义的BroadcastReceiver子类mXRReceiver & IntentFilter mBroadcastReceiver
mXRReceiver = new mXRReceiver();
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);

粘性广播

Android5.0之后已经废弃,不推荐使用

App1能否接收到App2的广播?

能,只要使用全局的BroadCastRecevier能进行跨进程通信,不过只能被动接收广播。 多说一句,当然不能用LocalBroadCastRecevier,这个只限于本进程内部的广播。

Powered by Hexo & Theme Keep
Unique Visitor Page View