说明:BroadcastReceiver——广播接收者,是Android四大组件之一,在实际的开发过程中BroadcastReceiver的应用场景非常多,本篇文章将详细讲解一下BroadcastReceiver,如果各位码友发现文中说明存在问题欢迎指正,CV操作请注明出处,谢谢!
1、定义说明。
BroadcastReceiver即广播接收者,是Android四大组件之一,是一个全局的监听器。在Android中广播分为广播发送者和广播接收者,广播发送者(一般是其他的组件进行sendBroadcast操作),广播接收者(BroadcastReceiver)对发送出来Broadcast进行过滤、接收和响应。
2、使用场景。
Android不同组件间的通信(包括进程内和进程之间,同一App和不同App)。
与Android系统通信(如开机、网络状态、安装/卸载应用等)。
3、内部机制(原理)。
设计模式:采用了观察者模式,基于消息的发布/订阅事件模型,使得广播的发送者和广播的接收者进行解耦。
参与角色:广播(消息)发送者、广播(消息)接收者、AMS(ActivityManagerService)
实现步骤概况:
1、广播接收者通过Binder机制在AMS注册。
2、广播发送者通过Binder机制在AMS发送广播。
3、AMS根据广播发送者的要求,在注册列表中,根据IntentFilter /Permission查找目标广播接受者。
4、AMS将广播发送给目标广播接收者的消息队列中。
5、广播接收者通过消息队列获取消息,然后回调onReceive()。
4、使用介绍。
4.1、广播的接收。
广播接收者的使用大概分为三步:创建广播接收者、注册广播接收者、根据需求实现逻辑。
4.1.1 、创建广播接收者。继承BroadcastReceivre,复写抽象方法onReceive()。
public class XxxReceiver extends BroadcastReceiver {
private static final String TAG = "XxxReceiver";
public XxxReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
//处理业务逻辑等,如发送Notification、启动Service等
}
}
注意:onReceive运行在UI线程中,因此,onReceive()方法不能执行耗时操作,否则将导致ANR
另外不要在此有开启子线程的操作,会造成内存泄漏,如果需要请采用其他方式或者IntentService。
4.1.2 、注册广播接收者(Android 8.0大部分静态注册广播失效,仅剩下较少的系统广播可以静态注册)。
1、静态注册,即在清单文件中为BroadcastReceiver进行注册,使用<receive >标签声明,并在标签内<intent-filter >标签设置过滤器。
这种形式的 BroadcastReceiver 的生命周期伴随着整个应用,如果这种方式处理的是系统广播,那么不管应用是否在运行,该广播接收器都能接收到该广播
<receiver android:name=".XxxReceiver">
<intent-filter>
<action android:name="com.example.leisure.yyy" />
<!--过滤属性,只有具有该属性的广播才会被接收-->
</intent-filter>
</receiver>
<XxxReceiver
广播接收者为四大组件之一,也具有下边的较为常用的属性
android:exported="true"<!--外部应用是否可以调用,默认为true,如果不对外开放,建议false-->
android:permission=""<!--具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收-->
android:process=""<!--指定进程-->
android:enabled=""<!--能否接收其他App的发出的广播-->
2、动态注册。即在代码中定义并设置好一个IntentFilter对象,然后在需要注册的地方调用Context.registerReceiver()方法,调用Context.unregisterReceiver()可以取消注册。
@Override
public void onCreate() {
super.onCreate();//注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.leisure.yyy");//
receiver = new XxxReceiver();
registerReceiver(receiver, intentFilter);
}
@Override
public void onDestroy() {
super.onDestroy();//取消注册广播
unregisterReceiver(receiver);
}
注意:动态广播的注册和取消注册须要成对出现。如果Activity/Fragment中建议在onResume()注册、onPause()注销广播因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露。除非必要不建议在onCreate()/onDestory() 或 onStart()/onStop()注册、注销,因为当系统因为内存不足(如优先级更高的应用需要内存)要回收Activity占用的资源时,Activity在执行完onPause()方法后就会被销毁,有些生命周期方法onStop(),onDestory()就不会执行。
当再回到此Activity时,是从onCreate方法开始执行,造成内存泄漏。
4.2、广播的发送。
4.2.1、广播的分类,可分为5种:Normal Broadcast、System Broadcast、Sticky Broadcast、Local Broadcast。
1、普通广播(Normal Broadcast)。
最为常用的广播,一般需要添加action,声明了对应的action的广播接收者才能收到广播,即onReceive()回调。如果添加了权限,则广播接收者也需要在注册的时候明确权限。
Intent intent = new Intent();
//对应BroadcastReceiver中intentFilter的action,
intent.setAction("com.example.leisure.yyy");
//发送广播
sendBroadcast(intent);
2、系统广播(System Broadcast)。
系统广播,不需要app去发送,由系统根据情况自动发送,app只负责接收(如果需要)。
3、有序广播(Ordered Broadcast)。发送出去的广播被广播接收者按照先后顺序接收,有序是针对广播接收者而言的。
广播接受者接收的顺序规则是按照Priority属性值从大到小排序(同一Priority,动态注册的广播优先级大于静态注册的广播);
先接收的广播接收者可以对广播进行拦截,小优先级的广播接收者将无法收到该广播;
先接收的广播接收者可以对广播进行修改,小优先级的广播接收者将接收到被修改后的广播。
示例:
Intent intent = new Intent("com.receiver.leisure.common");
intent.putExtra("xxx", "有序广播");
sendOrderedBroadcast(intent, null);//发送有序广播
//此处忽略了注册过程。
public class OrderReceiverXxx extends BroadcastReceiver {//第一优先级
public OrderReceiverXxx() {
}
@Override
public void onReceive(Context context, Intent intent) {
//取出Intent当中传递来的数据
String msg = intent.getStringExtra("xxx");
//向下一优先级的Receiver传递数据
Bundle bundle = new Bundle();
bundle.putString("yyy", "xxx修改了广播");
setResultExtras(bundle);
}
}
public class OrderReceiverYyy extends BroadcastReceiver {//第二优先级
public OrderReceiverYyy() {
}
@Override
public void onReceive(Context context, Intent intent) {
//取出上一优先级的Receiver传递来的数据
String data = getResultExtras(true).getString("yyy");
//拦截广播
abortBroadcast();
}
}
public class OrderReceiverZzz extends BroadcastReceiver {//第三优先级
public OrderReceiverZzz() {
}
@Override
public void onReceive(Context context, Intent intent) {
//收不到广播了
}
}
4、粘性广播(Sticky Broadcast)。Android5.0(API 21)中已经失效,可忽略。
5、本地广播(Local Broadcast)。
由于Android中的广播可以跨进程(App)通信,不同的App注册的广播intent-filter可能会相同,也存在其他App根据intent-filter针对性的恶意发送某些广播造成安全或者效率问题。
Android内提供了本地广播,广播的发送者和接收者都同属于一个App,提高了效率和安全性。
针对普通广播效率和安全性的问题,一般有两种方式:
1、注册广播时候将exported属性设置为false;增设相应权限permission,用于权限验证;发送广播指定包名。
2、建议使用本地广播的形式。
本地广播是使用LocalBroadcastManager来对广播进行管理,和普通广播存在注册、发送的方式的细微差别,除此之外都一样。
LocalBroadcastManager.getInstance(this).registerReceiver(BroadcastReceiver, IntentFilter)
注册Receiver
LocalBroadcastManager.getInstance(this).unregisterReceiver(BroadcastReceiver);
注销Receiver
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent)
发送异步广播
LocalBroadcastManager.getInstance(this).sendBroadcastSync(Intent)
发送同步广播
5、注意事项。
1、不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的,静态注册的广播是ReceiverRestrictedContext;动态注册的广播是Activity Context;本地广播是Application Context。