是什么
BroadCastReceiver是四大组件之一,相当于一个全局的监听器,用于监听系统全局的广播。
怎么样
由于BroadCastReceiver是全局监听器,因此它可以方便的实现系统中不同组件之间的通信。
怎么用
实现步骤分三步
- 创建BroadCastReceiver
- 创建需要启动BroadCastReceiver的Intent
- 调用Context的sendBroadCast或sendOrderBroadCast方法启动指定的receiver
receiver需要继承BroadCastReceiver并实现onReceive方法,当程序发出一个BroadCast的Intent之后所有匹配了改Intent的BroadCastreceover都有可能会被启动
与Activity和Service不同的是BroadCastReceiver生命周期比较短,本质是一个系统级全局的监听器,专门负责监听个程序所发出的BroadCast
实现了BroadCastReceive就要有与只匹配的Intent
两种匹配intent方式
- 在代码中动态设置,通过intentFilter设置Action
- 在AndroidMainifest中的receiver标签中设置Action
值得注意的是:
- 执行完onReceiver后实例会被销毁,生命周期短
- 发送广播后如果没有与之匹配的receiver,程序不会报错,这与Activity和Service不同
- 不能在onReceiver方法中做耗时操作,10秒内onReceive方法没有执行完成会被认为程序无响应,因此耗时操作应该在Service中开启线程来执行
两种发送广播的方式
- sendBroadCast()普通广播
- sendOrderBroadCast()有序广播
有序广播会根据优先级别按顺序执行接收者,优先接到的可通过abortBroadCast来终止广播,也可以通过setResultExtra()来修改接收到的值并传递,下一个广播在通过getResultExtra()来获取。
两种注册方式
- 动态注册,广播会跟随程序的生命周期,在Activity或service中注册,但是必须到onDestroy中销毁,不然会报错
- 静态注册,常驻型,即使应用关闭,也能够接收广播
代码演示
xml里面两个按钮,一个动态注册,一个静态注册
按照前面说的第一步,先创建一个类TestReceiver
继承BroadcastReceiver
,该类是一个抽象类,需要实现里面的抽象方法onReceive(Context context, Intent intent)
public class TestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = intent.getStringExtra("sky");
Log.d("TestReceiver", "接收到的值" + sky);
}
}
这里面的Intent
就是接收传过来的值
第二步,创建匹配该broadCastReceiver
的Intent
,首先要给broadCastReceiver
设置一个Action,然后再通过给Intent设置Action,如果Intent的Action与broadCastReceiver
的Action匹配,也就是一样,则broadCastReceiver
将会被系统启动,接收到Intent传过来的消息。首先注册广播,由上面可知注册有动态注册和静态注册,
- 动态注册代码
receiver = new TestReceiver();
registerReceiver(receiver, new IntentFilter(ACTION));
由于动态注册广播会跟随程序的生命周期,所以注册时实例化应该声明为全局变量,以便在onDestroy中注销,否则会报错!
通过registerReceiver方法来动态注册广播,参数1是被注册的广播,参数2是IntentFilter,设置broadCastReceiver的Action,
2. 动态注册代码
<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
在AndroidMainifest中注册,这是常驻性注册,即使应用被关闭,接收到匹配的Action,广播也能被启动,也是通过Iintent-filter标签来设置Action。
这两种注册方式,根据需求进行选择,选择动态注册,务必记得手动注销
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
第三步,发送广播,注册好了广播,就可以使用了,在按钮的点击事件中添加如下代码
/**
* 匹配Intent,与这个Action相同的接收者都会接收到。
*/
Intent intent = new Intent();
intent.setAction(ACTION);
intent.putExtra("sky", "I appreciate the man who are goood at Android");
sendBroadcast(intent);
这里的ACTION与注册广播时的ACTION要一样,否则匹配失败,无法接收
public static final String ACTION = "com.cd.broadcastreceiver";
这个ACTION字符串可以是任意的,但是为了看起来规范,选择包名的形式。
点击按钮看到如下输出
说明广播是接收到了。
这里是一个接收者一个发送者,而且匹配的ACTION一致,如果有多个接收者匹配了同一个发送者的ACTION会不会都收到,或者多个接收者之间有没有相互的影响呢?
在上面的基础上添加另外两个接收者TestReceiver2
和TestReceiver3
,然后我选择静态注册
<!--<receiver android:name=".TestReceiver"/>-->
<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
<receiver android:name=".TestReceiver2">
<intent-filter>
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
<receiver android:name=".TestReceiver3">
<intent-filter>
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
这里三个接收者都是设置的相同的ACTION.
发送代码不变,点击按钮输出如下
三个都接收到了,而且输出顺序是按照AndroidMainifest注册顺序输出的,不确定这两者之间有没有关系,知道的麻烦告诉我一声。
接着我在第一个广播的onReceiver 方法中添加了abortBroadcast();
终止广播。
再次运行,输出如下
还是接收到了,表明接收者不能终止广播,注意到在abortBroadcast
的地方报了个错,这个先不管,
那么如何终止广播或者在广播传播的过程中修改广播内容呢?可以使用有序广播
有序广播每次只发送到优先级高的那里,然后由优先级高的依次往优先级低的发送,优先级高的可以决定终止或继续传播这个广播。
修改之前三个接收者的代码如下
第一个广播TestReceiver
public class TestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = intent.getStringExtra("sky");
Log.d("TestReceiver", "接收到的值" + sky);
Bundle bundle=new Bundle();
bundle.putString("message",sky+"from TestReceiver");
setResultExtras(bundle);
}
}
第二个广播TestReceiver2
public class TestReceiver2 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = getResultExtras(true).getString("sky");
Log.d("TestReceiver2", "接收到的值" + sky);
Bundle bundle=new Bundle();
bundle.putString("message",sky+"message from TestReceiver2");
setResultExtras(bundle);
}
}
第三个广播TestReceiver3
public class TestReceiver3 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String sky = getResultExtras(true).getString("sky");
Log.d("TestReceiver3", "接收到的值" + sky);
}
}
通过setResultExtras
写入数据,getResultExtras
获取数据
AndroidMainifest修改如下
<!--<receiver android:name=".TestReceiver"/>-->
<receiver android:name=".TestReceiver"
>
<intent-filter android:priority="10">
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
<receiver android:name=".TestReceiver2">
<intent-filter android:priority="9">
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
<receiver android:name=".TestReceiver3">
<intent-filter android:priority="8">
<action android:name="com.cd.broadcastreceiver"></action>
</intent-filter>
</receiver>
注意到,在intent-filter标签下,添加了android:priority
属性,这是是设置广播的优先级,取值范围是-1000~1000,值越大,优先级越高,如果没有设置优先级会报这个错
BroadcastReceiver trying to return result during a non-ordered broadcast
而且只有第一个声明的能接收到,后面的无法接收。
修改发送广播的代码
Intent intent1 = new Intent();
intent1.setAction(ACTION);
intent1.putExtra("sky","register in AndroidMainifest");
sendOrderedBroadcast(intent1,null);
将sendBroadcast
改为sendOrderedBroadcast
,这里多了一个权限参数,null表示不用权限,想了解权限可看这篇文章Android声明和使用权限
修改完,点击按钮输出为
由图可以看到,接收顺序是按照优先级来执行的,以及传递的值也是依次接收到了,【这里有个疑问,在输出的最后一行,第一个广播又输出了一次,这个很不可思议,不是广播在onReceive方法执行完后,实例就被摧毁了么,为什么会执行两次呢?如果有人看到这篇文章,并且知道造成的原因,麻烦告诉我一下,谢谢】
现在再次在TestReceiver的onReceiver中调用abortBroadcast();
输出如下
可以看到,优先级高的接收到了广播,后面优先级低的就被终止了,而且没有报之前那个错了。所以abortBroadcast
要在有序广播中使用。