一、了解
1. 定义
BroadcastReceiver(广播接收器)即广播,是一个全局的监听器。
2. 意义
用于响应来自应用APP或者系统的广播消息
3. 应用场景
- 同一 App 内部的同一组件内的消息通信(单个或多个线程之间);
- 同一 App 内部的不同组件之间的消息通信(单个进程);
- 同一 App 具有多个进程的不同组件之间的消息通信;
- 不同 App 之间的组件之间消息通信;
- Android系统在特定情况下与App之间的消息通信,如:网络变化、电池电量、屏幕开关等
二、注册
首先创建一个类,继承自BroadcastReceiver,并重写onReceiver()方法。onReceiver()方法中的内容就是当广播接收器接收到广播时要处理的事务。这里就是简单的发出一条toast。
public class BroadcastReceiverTest extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "这是一条广播~", Toast.LENGTH_SHORT).show();
}
}
注册分为两种注册方式,一种为静态注册,一种为动态注册, 下面将会分别讲解两种注册方式,并会对两种注册方式进行一个对比。
1. 静态注册
静态注册需要在AndroidManifest.xml清单文件中进行注册
- 在AndroidManifest中的application标签下加上receiver子标签
- 通过"android: name= "注册一个广播类(其中name后需写出你要注册的文件路径)
- android:enabled="true" 代表是否允许该广播接收器接受本程序以外的广播
- android:exported="true" 代表是否启用这个广播接收器
- 在receiver下加上intent-filter标签,设置其action,里面的内容可以是系统定义的系统广播的“频道”,也可以是自定义的广播的“频道”
<receiver
android:name="com.example.mytest.BroadcastReceiverTest"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.REBOOT" /> <!-- 设备重启广播 -->
</intent-filter>
</receiver>
想监听什么广播,就添加相应的action标签。(注意:一些系统广播是需要声明权限的)
(intent-filter标签可以理解为过滤器,当系统中出现与过滤器中标签相符的广播时,便代表接收到了广播,开始执行广播接收器中的onReceiver()方法)
如果你想监听多条广播也是可以的,添加多个intent-filter标签即可
<receiver
android:name="com.example.mytest.BroadcastReceiverTest"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_ACL_CONNECTED" /> <!-- 设备重启 -->
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- 在系统完成启动后广播一次 -->
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DATE_CHANGED" /> <!-- 日期发生改变 -->
</intent-filter>
</receiver>
些人问 Android 8.0不是取消大部分静态注册广播了吗?没关系,后文有解决的办法,请继续向下看。
2.动态注册
动态注册只需要在java文件中进行注册即可
- 创建一个广播接收器类的对象 "broadcastReceiverTest"
- 创建一个IntentFilter类的对象 "intentFilter"
- 调用intentFilter的.addAction()方法存入广播“频道”
- 最后,调用context.registerReceiver(broadcastReceiverTest, intentFilter)方法注册,其中,第一个参数为广播接收器的对象,第二个参数为IntentFilter类的对象
IntentFilter intentFilter = new IntentFilter();
BroadcastReceiverTest broadcastRecevierTest = new BroadcastReceiverTest();
intentFilter.addAction("com.example.mytest.BroadcastReceiverTest"); //这是一条自定义的广播
registerReceiver(broadcastRecevierTest, intentFilter);
这样一条动态注册就注册成功了,注册成功后还需要记得,动态注册的广播接收器一定要取消注册才行,否则可能会引起内存泄漏。
一般可以选择写在onDestroy()方法中,当然,如果你担心Activity没有执行到onDestroy()方法,你也可以写在onStop()方法中。
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiverTest);
}
3.注册方式对比
- 静态注册依附于清单文件,只要APP启动过一次,所静态注册的广播就会生效,无论当前的APP处于停止使用还是正在使用状态。只要相应的广播事件发生,系统就会遍历所有的清单文件,通知相应的广播接收者接收广播,然后调用广播接收者的onReceiver方法。
- 动态注册方式依赖于所注册的组件,当APP关闭后,组件对象都不在了动态注册的代码都不存在了,所动态注册监听的action自然不在生效。
- 静态注册的广播传播速度要远远慢于动态注册的广播。
4.提示
到目前为止,我们在广播接收器的onReceive()方法中都只是简单的用Toast提示了一段文本信息,当你在项目中时可以编写自己的逻辑,但要注意的是,不要在onReceive()方法中添加过多的逻辑或者进行任何耗时的操作,因为广播接收器是不允许开启线程的,当onReceive()方法运行了较长时间没有结束时,程序就会报错。
三、发送广播
发送广播分为三种方式,分别为标准(无序)广播、有序广播、本地广播。
1. 发送标准(无序)广播
标准广播是所有与之匹配的广播接收者都能收到的广播,没有先后顺序,直到没有广播接收者接收广播为止才会停止广播的传递。
- 首先创建一个Intent对象,把广播的“频道”值传入
- 然后调用context的sendBroadcast()方法将广播发送出去,参数为刚才创建的Intent对象
- 之后, 所有监听“com.example.mytest.BroadcastReceiverTest”这条频道的广播接收器就会收到该广播
Intent intent = new Intent("com.example.mytest.BroadcastReceiverTest");
sendBroadcast(intent);
注意:由于广播是使用Intent传递的,因此可以在Intent中携带一些数据进行传递。
2. 发送有序广播
有序广播是一种分先后广播接收器的广播,广播接收者的优先级越高,越先接收广播。优先级高的广播先收到广播,收到广播后可以修改广播的内容,也可以拦截广播不让广播向下传递。
有序广播和无序广播步骤相同,不同点便是将sendBroadcast()方法换成sendOrderedBroadcast()方法
- 首先创建一个Intent对象,把广播的“频道”值传入
- 然后调用context的sendOrderedBroadcast()方法将广播发送出去,第一个参数为刚才创建的Intent对象,第二个参数是与权限相关的字符串,一般不用时填写null即可
- 之后, 所有监听“com.example.mytest.BroadcastReceiverTest”这条频道的广播接收器就会收到该广播
Intent intent = new Intent("com.example.mytest.BroadcastReceiverTest");
sendOrderedBroadcast(intent,null);
由于有序广播是分优先级的,那么如何设置优先级呢?
第一种方法是静态注册时在Intent-filter标签中设置
<receiver
android:name="com.example.mytest.BroadcastReceiverTest"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.mytest.BroadcastReceiverTest" /> <!-- 设备重启 -->
</intent-filter>
</receiver>
或者在动态注册时调用IntentFilter类对象的setPriority()方法来设置
IntentFilter intentFilter = new IntentFilter();
BroadcastRecevierTest broadcastRecevierTest = new BroadcastReceiverTest();
intentFilter.addAction("com.example.mytest.BroadcastReceiverTest"); //这是一条自定义的广播
intentFilter.setPriority(100); //设置广播的优先级
registerReceiver(broadcastRecevierTest, intentFilter);
广播优先级取值的范围为-1000~10000,数值越大优先级越高,优先级高的广播可以先收到并选择截断广播,截断广播只需要在你重写的onReceive()方法中加入abortBroadcast()方法即可,后面的广播接收器将不再接受此广播,你也可以存入新的数据向后继续传递。
3. 本地广播
前面我们的发送与接收都属于系统全局广播,即发出的广播可以被任何其他APP收到,我们也可以接收到任何其他APP的广播,这样容易引起安全问题。
为了能简单的解决安全问题,Android引入了本地广播,本地广播是只在APP内部进行传递的一种广播方式,它的好处在于不会引起安全问题,不用担心数据的泄露。
本地广播和标准广播步骤基本一样,只是使用了一个LocalBroadcastManager(需要添加依赖)来对广播进行管理,相比标准广播只是每一个步骤多添加了一段代码。
- 本地广播的创建首先先引入一个LocalBroadcastManager类
- 然后通过LocalBroadcastManager的getInstance()方法获取他的一个实例
- 然后注册时调用的是LocalBroadcastManager类对象的registerReceiver()方法
- 发送时调用的是LocalBroadcastManager类对象的sendBroadcast()方法
- 取消注册时调用的也是LocalBroadcastManager类对象的unregisterReceiver()方法
public class LocalBroadcastRecevierTest extends AppCompatActivity {
private Button bt_am_baroadcastreciver;
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager = LocalBroadcastManager.getInstance(this); //获取实例
bt_am_baroadcastreciver = findViewById(R.id.bt_am_baroadcastreciver);
bt_am_baroadcastreciver.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.mytest.BroadcastReceiverTest");
localBroadcastManager.sendBroadcast(intent); //发送本地广播
}
});
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.mytest.BroadcastReceiverTest");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter); //注册本地广播监听器
}
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver); //取消注册
}
}
class LocalReceiver extends BroadcastRecevierTest{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "这是一条本地广播~", Toast.LENGTH_SHORT).show();
}
}
注意:本地广播是无法通过静态注册来注册的,因为他的目的只是在APP内部传递消息,也就用不到静态注册。
本地广播的优势:
- 广播不会离开程序,不用担心泄露数据。
- 其他程序无法将广播发送到我们程序内部,不用担心安全漏洞隐患。
- 本地广播比系统全局广播更加高效。
四、Android8.0后的静态注册
Android 8.0以上可以使用setComponent()来指定包名和类名 。
在注册时调用Intent类对象的setComponent()方法。
Intent intent = new Intent("com.example.mytest.BroadcastReceiverTest");
//使用setComponent()方法,这一行在Android 7.0及以下版本不是必须的,但是Android 8.0或者更高版本,发送广播的条件更加严苛,必须添加这一行内容。
intent.setComponent(new ComponentName("com.example.mytest", "com.example.mytest.BroadcastReceiverTest"));
//创建的ComponentName实例化对象有两个参数,第1个参数是指接收广播类的包名,第2个参数是指接收广播类的完整类名。
sendBroadcast(intent,null);
这样,你就可以接收到静态注册的广播了。
五、总结
以上内容就是BroadcastReceiver的全部内容了,总结下来,个人认为关于BroadcastReceiver总共就三个部分,注册、发送、接收器,注册分为静态和动态,发送分为标准(无序)、有序、本地,接收器靠的是继承BroadcastReceiver类重写onReceive()方法。记住这些广播就不是难事了~