BroadcastReceiver
Broadcast 是一种广泛运用在一个设备中不同应用程序之间传输信息的机制。而BroadcastReceiver 是对发送出来的Broadcast进行过滤接受并响应的一类组件。可以使用BroadcastReceiver 来让应用对一个外部的事件做出响应。
但是BroadcastReceiver生命周期很短 不能做耗时操作 要提交给service
设置广播接收方式
可分为普通广播 和 有序广播
普通广播:
sendBroadcast(intent)
所有接受者都可以同时接收到,接收者相互之间不会有影响,不能终止别的接受者接收
有序广播
sendOrderBroadcast(Intent intent,String permission)
有序广播 可以截断 可以处理数据(比如广播给第一个,然后第一个收到后可以传递一些数据给第二个)
在注册广播中的< intent-filter>中使用android:priority属性。这个属性的范围在-1000到1000,数值越大,优先级越高
第二个参数为 权限 设置为null 则 表示不要求接收者声明指定的权限,如果不为null则表示接收者若要接收此广播,需声明指定权限
例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递 这时软件就要通过权限设置拦截短信
在广播接收器中使用setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者那里,这样优先级低的接收者可以用getResuttExtras获取到最新的经过处理的信息集合
静态注册(无论应用程序是否运行 receiver都会监听相应注册过的action)
一、File->new ->others->brocardReveiver
通过该方式自动生成 继承brocardReveiver的类
并且会在 manifest.xml中自动注册
否则要自己去manifest.xml中注册
<receiver
android:name=".Utils.TestReceiver"
android:enabled="true"
android:exported="true"></receiver>
android:enabled
android:enabled属性来限制Android系统的行为。这个属性表明Android系统是否可以被实例化应用程序组件,如果其值为true,则说明应用程序组件可以被Android系统自动实例化;如果为false,则说明实例化组件的工作需要手工完成
android:exported
是否支持其它应用发送广播到该app 若配置了<intentfilter 则默认为true 否则默认为false
二、设置接收的广播action
<receiver
android:name=".Utils.TestReceiver"
android:enabled="true"
android:exported="true">
<intent-filter
<!--设置静态广播优先级-->
<!--android:priority="1000"-->
>
<action android:name="NetStatusAction" />
</intent-filter>
</receiver>
三、重写onReceive方法
当接收到广播信息时,则会执行该方法
onReceive方法不能执行耗时操作(15s) 要去开启子线程或者通过serivce进行耗时操作
public class TestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(("NetStatusAction").equals (action)){
Toast.makeText(context,"NetStatusAction执行",Toast.LENGTH_SHORT).show();
}
}
}
四、发送广播
Intent intent = new Intent();
intent.setAction("NetStatusAction");
sendBroadcast(intent);
动态广播 (与Activity或applicationContext生命周期有关)##
一、创建类继承BroadcastReceiver,重写onReceive方法,类似上面
如 DynamicReceiver
二、
// 声明动态广播
DynamicReceiver dynamicReceiver;
// 相应事件中
IntentFilter filter = new IntentFilter();
filter.addAction("xxxAction");
//设置动态优先级
//filter.setPriority(1000);
dynamicReceiver = new DynamicReceiver();
(applicationContext.)registerReceiver(dynamicReceiver,filter);
三、相应的onDestroy或者onStop中,解除注册
如果是applicationContext注册的得通过applicationContext解注册 通过activity解注册并不是真正的解注册
(applicationContext.)unregisterReceiver(dynamicReceiver);
如果多个界面中要解注册 则可以用一个单例的广播,或者每个界面去register/unregister
两种方式的主要区别:
1 静态方式 系统会唤醒应用 去接收广播
2 静态方式 系统会创建一个新的BroadcastReceiver组件对象去接收每一个广播(接收一个创建一个 因此不能在构造函数或者在类中创建对象和内存)
会在onReceive的持续时间内有效 一旦该函数返回 则对象销毁
而动态方式则可以自己设置广播注册和注销的时间
3 动态方式比静态方式开启速度快
4 静态方式注册的广播,如果要在内部类中,必须要声明为public static,否则会报错
版本改动:
在Android7.0以上 无法使用清单声明隐式(implicit)广播的接收者(不针对本地应用的广播),除了几个免除该限制的隐式广播。
在Android8.0以上 无法在清单文件中为绝大多数隐式广播(不针对你应用的本地广播)声明接收者
在大多数情况下,您可以使用Jobscheduler针对特殊系统消息进行相应接收和处理。
在Android9.0以上 NETWORK_STATE_CHANGED_ACTION broadcast不能获取用户的地址位置信息了
系统的WIFI广播 不再包含SSIDs, BSSIDs, connection information, or scan results信息了
得通过 getConnectionInfo() 获取
LocalBroadcastManager
优点:
广播是重量级的、消耗资源较多的方式,因此若只是在自己的app内进行广播,可以采用LocalBroadcastManager 更安全高效
1 发送的广播是在APP内的,不会泄漏到别的APP中,并且别的APP的广播也不会接收,更安全
2 比BroadcastReceiver更高效
缺点
只能实现app内的广播,不同app间,以及系统的广播还是得用BroadcastReceiver 不能跨进程通信
与BroadcastReceiver的根本区别 :
BroadcastReceiver底层是Binder机制,因此可以实现跨进程通信,而LocalBroadcastManager 是Handler
基于主线程的 Looper 新建了一个 Handler,handleMessage中会调用接收器对广播的消息进行处理
基本使用:
一、创建自定义接收器
public class LocalBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//TODO
}
}
二、注册广播接收器
LocalBroadcastReceiver localReceiver = new LocalBroadcastReceiver();
LocalBroadcastManager.getInstance(applicationContext)
.registerReceiver(localReceiver, new IntentFilter(ACTION_LOCAL_SEND));
这里的IntentFilter可以自定义不同的Action 类似BroadcastReceiver的IntentFilter
三、发送广播
LocalBroadcastManager.getInstance(applicationContext)
sendBroadcast(new Intent(ACTION_LOCAL_SEND));
四、注销广播接收器
LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(localReceiver);
注意的点:
1 LocalBroadcastManager没有优先级的设置
2 LocalBroadcastManager最好传系统的applicationContext 否则容易造成内存泄漏
系统广播
问题1 若发送了非protected的广播 会打印这个日志:
E/ActivityManager: Sending non-protected broadcast
该异常已被ActivityManager捕获,并不会导致crash
原因:
app是系统app 发送了一个不带protected-broadcast属性的广播
系统app:
设置了uid为 android.uid.system,android.uid.phone,android.uid.log,android.uid.nfc,android.uid.bluetooth,android.uid.shell
的并且被签过名的app是系统app
或者在指定目录中的app为系统app “指定目录”包括/vendor/overlay,/system/framework,/system/priv-app,/system/app,/vendor/app,/oem/app
解决:
1 给该广播加上protected-broadcast属性
<protected-broadcast android:name="android.intent.action.XXX_ACTION" />
这样 这种action只能由系统app发起,而不能由非系统app发起 否则会引起crash