广播在Android开发中的使用十分广泛,其功能由发送者和接收者两部分组成,与现实中的广播类似,广播台通过信号塔发射广播信号(发送广播),用户通过收音机(广播接收者)来接收广播内容。其中广播接收者是Android的四大组件之一。
1.广播的基本使用:
1.1 创建并发送广播:
广播发送时也是使用Intent作为载体的
Intent intent = new Intent();
intent.setAction("test.broadcast");//
intent.putExtra("test","string extra");
context.sendBroadcast(intent);
1.2 创建广播接收者
public class TestBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "TestBroadcastReceiver";
@Override
public void onReceive(Context context, Intent intent) {
//处理接收到广播后的逻辑
}
}
1.3 注册与反注册广播接收者
广播接收者的注册分为静态注册和动态注册
静态注册在Manifest文件中application标签下:
<receiver android:name=".boardcastReceiver.TestBroadcastReceiver"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="test.broadcast" />
</intent-filter>
</receiver>
name就是Receiver类的名称
exported表示这个接收者是否接收其他进程app发送的此广播
priority为优先级,最大为1000
action的name就是创建广播时指定的action
动态注册在代码中:
private TestBroadcastReceiver receiver;
@Override
protected void onCreate() {
super.onCreate();
receiver = new TestBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("test.broadcast");//广播的action
registerReceiver(receiver,intentFilter);//注册广播,通常时在Activity OnCreate的时候
//也可以不编写BroadcastReceiver的子类TestBroadcastReceiver直接使用匿名内部类的方式创建Receiver
receiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
//处理接收到广播后的逻辑
}
};
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);//在onDesdory的时候取消广播的注册,防止内存泄漏
}
需要注意动态注册的广播接收者优先级永远比静态注册的广播接收者要高,静态注册的广播接收者则生命周期要比动态注册的要长。Android 8.0之后对广播的静态注册做了限制,自定义的广播接收者静态注册的时候会收不到广播。为了程序安全谷歌建议开发者使用动态注册。如果一定要静态注册一对一广播可以在发送广播的时候给intent设置目标app的包名,这样就可以收到了。
Intent intent = new Intent();
intent.setAction("test.broadcast");
intent.setPackage("com.example.testapp");
sendBroadcast(intent);
如果需要一对多的话目前只能让别的app动态注册广播接收者了,或者降低target sdk version等级在25以下了。
以前google隐藏了一个flag可以在intent中设置FLAG_RECEIVER_INCLUDE_BACKGROUND(0x01000000)来让静态注册的app接收广播
intent.addFlags(0x01000000);
目前我在新版本的sdk中发现已经无法使用
所以大家还是老老实实动态注册吧~
2 广播的分类:
广播的分类有好几种,首先可以分为标准广播和有序广播
2.1标准广播
标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接受到这条广播消息,因此它们之间没有任何先后顺序可言,这种广播的效率会比较高,但同时也意味着它是无法被拦截的。
2.2有序广播
有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接受器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。
有序广播通过sendOrderedBroadcast方法发送
Intent intent = new Intent("test.broadcast");
sendOrderedBroadcast(intent,null);
第二个参数为启动权限,设置为null也就是不添加权限
官方对这个参数的介绍是:
receiverPermission (optional) String naming a permissions that a receiver must hold in order to receive your broadcast. If null, no permission is required.
也就是说开发者可以自定义一个权限,如果广播接收者所在的app没有去声明这个权限,那么它就无法接收到这条广播。
广播接收者需要申明自己的优先级
对于静态注册:
<receiver android:name=".boardcastReceiver.TestBroadcastReceiver"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="test.broadcast" />
</intent-filter>
</receiver>
动态注册:
receiver = new TestBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("test.broadcast");
intentFilter.setPriority(999);
registerReceiver(receiver,intentFilter);
注意虽然静态注册的优先级设置为了1000,动态注册为999,但是还是动态注册的广播先收到,因为动态注册永远比静态注册优先级高。
先收到广播的接收者有权限中断有序广播的继续发送,只需在onReceive中调用
abortBroadcast()即可
@Override
public void onReceive(Context context, Intent intent) {
//处理接收到广播后的逻辑
abortBroadcast()
}
2.3 粘性广播(不建议使用)
粘性广播也属于标准广播,在发送后就一直存在于系统的消息容器里面,等待对应的处理器去处理,如果暂时没有处理器处理这个消息则一直在消息容器里面处于等待状态,粘性广播的Receiver如果被销毁,那么下次重建时会自动接收到消息数据。
注意:普通广播和粘性消息不同被截获,而有序广播是可以被截获的。
在Android系统粘性广播一般用来确保重要的状态改变后的信息被持久保存,并且能随时广播给新的广播接收器,比如电源的改变,因为耗电需要一个过程,前一个过程必须提前得到,否则可能遇到下次刚好接收到的广播后系统自动关机了,随之而来的是kill行为,所以对某些未处理完的任务来说,后果很严重。
需要声明权限
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
发送粘性广播
Intent intent = new Intent();
intent.setAction(StickyBroadcastReceiver.Action);
intent.putExtra("test", "sticky broadcast has been receiver");
sendStickyBroadcast(intent);
接收到广播后调用
removeStickyBroadcast(intent);
取消粘性广播
2.4 系统广播
Android 内置了很多系统级别的广播,我们可以在应用中通过监听这些广播来得到各种系统的状态信息。比如手机开机后会发送一条广播,电池的电量发生变化会发出一条广播,时间或时区发生改变也会发出一条广播等等。如果想要接受这些广播,就需要使用广播接收器。
相应系统广播的Action可以通过文档查询,以开机广播为例
首先需要声明权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
高版本的环境中可能需要用户手动开启应用的自启动权限,而且这个广播只有应用安装过并且运行过才能收到。
接收和标准广播差不多,在manifest中静态注册
<receiver android:name=".boardcastReceiver.TestBroadcastReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
其他像电量(Intent.ACTION_BATTERY_CHANGED)这样的广播建议动态注册。
2.5 本地广播
广播的底层用到了Binder,我们知道Binder是Android用于跨进程通讯的。也就是说一个APP发送的广播其他APP也是可以接收的。这就存在了一个安全的问题,比如我知道了某个APP广播接收者的action,那么我就可以恶意发送广播给这个APP,为了解决这个问题就有了本地广播这个概念。也就是说发送本地广播只有本应用的receiver能收到。
Intent intent = new Intent("test.broadcast");
//发送本地广播
localBroadcastManager.sendBroadcast(intent);
注册接收者
localBroadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("test.broadcast");
LocalReceiver localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
本地广播无法通过静态注册接收,但是在静态注册的时候receiver标签下有android:exported="true"属性,设置为true就是允许接收其他进程发送的广播,false则只接收本地的。和本地广播的功能很相似。