BroadcastReceiver:
- Android四大组件之一,通过intent发送接收消息。系统本身也会发送广播,比如网络发生变化,屏幕的熄灭和亮起,接收短信,开机等这些行为都会发送广播。我们可以通过特定的、系统约定好的Action进行接收广播,来处理一些我们自己的逻辑。不过监听系统广播,大多是需要进行权限申请的。
- 分为有序广播、无序广播、本地广播
BroadcastReceiver的使用:
基本用法
继承 BroadcastReceiver 类,重写 onReceive 方法。
public class MyBroadcastReceiver1 extends BroadcastReceiver {
private static final String TAG = "广播接收者===";
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive: 我是动态注册的广播111111111111 "+hashCode());
}
}
注册广播
-
静态注册
在 AndroidManifest.xml 里面进行注册
<!--在设置action里面的name的时候,虽然可以随便设置,但是尽量用包名做 前缀,符合程序规则,这里为了测试就随便写了--> <receiver android:name=".broadcastreceiver.MyBroadcastReceiver3"> <intent-filter android:priority="1010"> <action android:name="test" /> </intent-filter> </receiver>
-
动态注册
首先创建实例
MyBroadcastReceiver1 myBroadcastReceiver1 = new MyBroadcastReceiver1();
注册广播
IntentFilter filter1 = new IntentFilter("test"); //设置优先级 filter1.setPriority(100); registerReceiver(myBroadcastReceiver1, filter1);
反注册广播
unregisterReceiver(myBroadcastReceiver1);
注意: 1. 一般我们在进行动态注册后,一定要进行反注册操作,避免资源浪费。反注册操作一般在 Activity 的 onDestroy 中进行 2.一定要在进行注册后才进行反注册操作,否则程序会直接崩溃。
发送广播
-
有序广播
Intent test = new Intent("test"); sendOrderedBroadcast(test,null); //or 下面方法为指定一个 最终广播接收者 此绑定着不受 中断广播影响,最终都会接收到广播。 //有意思的是,如果最终广播接受者的接收消息的优先级在其他广播接受者之上的时候,会先接收到消息,然后最终又会接收到一次消息,总共接收到两次消息。 sendOrderedBroadcast(test, null, myBroadcastReceiver1, null, 0, null, null);
-
可以通过abortBroadcast()进行中断广播,后面的广播接受者都不能进行接收广播。
-
可以通过在 onReceive 改变传递数据。
@Override public void onReceive(Context context, Intent intent) { Bundle bundle = new Bundle(); //传递数据 bundle.putString("aaa","我是接受者1"); setResultExtras(bundle); } /// @Override public void onReceive(Context context, Intent intent) { Bundle resultExtras = getResultExtras(true); //要对resultExtras 进行判空处理,如果前面没有传递数据,这里的resultExtras会为null //改变前面广播发送的数据 if(resultExtras!=null){ resultExtras.putString("aaa","我是接受者2"); } } //最终后面接收到的 "aaa" 的值为 "我是接受者2" /// @Override public void onReceive(Context context, Intent intent) { //中断广播 abortBroadcast(); }
-
sendOrderedBroadcast(test,null) 第二个参数是广播接受者指定所需的权限。
(这个有待研究, 在设置指定权限后,好像其他没有指定权限的广播接收者也能收到广播,懵逼。。。看到网上的提示:Android对同一PID的权限验证是直接通过的。因此如果Sender和Receiver在同一进程,是不能做权限限制的。 具体代码可以看一下ActivityManagerService的checkComponentPermission)
-
-
无序广播
Intent intent2 = new Intent("test"); sendBroadcast(intent2);
- 无法中断广播。
- 无序广播虽说官方文档上说是,接收消息的顺序是无序的,但是通过测试,还是有顺序的。
-
本地广播
使用 LocalBroadcastManager 进行发送本地广播和注册本地广播,只能发送无序广播。本地广播只能进行动态注册,其发送的广播只能在本进程中接收,注册的广播只能被本进程发送的广播接收。
//获取本地广播管理器单例 LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context); //注册本地广播 IntentFilter filter1 = new IntentFilter("test"); filter1.setPriority(100); localBroadcastManager.registerReceiver(myBroadcastReceiver1, filter1); //发送本地广播 Intent test = new Intent("test"); localBroadcastManager.sendBroadcast(test);
使用本地广播可以防止外部应用恶意接收我们的广播数据,并进行篡改。也可以防止外部应用恶意的发送垃圾广播给我们。
-
广播接收顺序
- 有序广播:
- 优先级(priority)高的优先于低的。
- 同优先级不同注册方式情况下,动态高于静态。
- 同优先级同注册方式情况下,动态注册:先注册的高于后注册的,静态注册:先扫描的优先于后扫描的。
- 无序广播:
- 动态注册高于静态注册,无视优先级。
- 不同优先级同注册方式,根据优先级高低进行排序。
- 同优先级同注册方式情况下,动态注册:先注册的高于后注册的,静态注册:先扫描的优先于后扫描的。
- 有序广播:
广播特点
- 广播接受者每次接收广播时,都会重新创建一个实例(可以通过打印其hashcode值进行验证)
- 优先级字段 priority 取值范围为 -1000-1000。(测试发现其实可以最大取到Integer.MAX_VAUE,就是2的31次方,2147483648)
- onReceive里不能进行耗时操作,因为广播接受者依赖于主线程,执行过久(网上看到说是10s)会报ANR(Application Not Response),也不建议在onReceive里面创建一个子线程进行耗时操作,因为在onReceive里面的业务逻辑执行完后,就有可能被系统回收,子线程依赖的活动组件被回收后,子线程任务有可能还没结束,此时会被标记为空进程,在内存吃紧的时候会被优先杀死回收。我们可以在Activity或者Service里面进行一些耗时操作。
Android8.0静态注册广播接收不到隐式发送的广播
在Android8.0以上,静态注册的广播,是接收不到隐式发送的广播的,只能接收通过显示方式发送的广播,也就是 intent.setComponent() 指定一个广播。
动态注册的广播不受影响。
Intent intent2 = new Intent("test");
intent2.setComponent(new ComponentName(this, MyBroadcastReceiver4.class));
sendBroadcast(intent2);
参考文献:
爱上Android书籍