壹 广播机制
- Android中的广播(Broadcast)机制用于进程/线程间通信,该机制使用了观察者模式。
- 观察者模式是一种软件设计模式,该模式是基于消息的发布/订阅事件模型,该模型中的消息发布者是广播机制中的广播发送者,消息订阅者是广播机制中的广播接收者,广播机制的具体实现流程,如下图所示。
- 广播接收者通过Binder机制在AMS(Activity Manager Service)中进行注册
- 广播发送者通过Binder机制向AMS发送广播。
- AMS查找符合相应条件(IntentFilter/Permission)的广播接收者(BroadcastReceiver),将广播发送到相应的消息循环队列中。
- 执行消息循环时获取到此广播,会回调广播接收者(BroadcastReceiver)中的onReceive()方法并在该方法中进行相关处理。
- Android系统中内置了很多广播,例如手机开机完成、电池电量不足时都会发送一条广播。为了监听来自系统或者应用程序的广播事件,Android系统提供了BroadcastReceiver(广播接收者)组件。
- 广播接收者的创建,具体如下:在应用程序的包中创建一个类继承BroadcastReceiver并重写onReceive()方法来实现的。
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
}
//在该方法中实现广播接收者的相关操作
@Override
public void onReceive (Context context, Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
1.1 动态注册
- 创建完广播接收者之后还需要对广播接收者进行注册才可以接收广播[一般在MainActivity中注册]
- 动态注册广播,动态注册的广播接收者是否被注销依赖于注册广播的组件,当组件销毁时,广播接收者也随之被注销。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//实例化广播接收者
MyReceiver receiver = new MyReceiver();
//实例化过滤器并设置要过滤的广播
String action = "android.provider.Telephony.SMS_RECEIVED";
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(action);
registerReceiver(receiver,intentfilter);//注册广播
}
protected void onDestroy() {
super.onDestroy();
//当Activity销毁时,取消注册
unregisterReceiver(receiver);
}
1.2 静态注册
- 静态注册广播,在小于Android8.0的设备上,只要设备处于开启状态,广播接收者就能接收到广播。
<?xml version="1.0" encoding="utf-8"?>
<manifest ………. >
<application ……… >
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
</application>
</manifest>
1.3 自定义广播
- 当系统提供的广播不能满足实际需求时,可以自定义广播,同时需要编写对应的广播接收者。
- 当自定义广播发送消息时,会储存到公共消息区中,而公共消息区中如果存在对应的广播接收者,就会及时的接收这条信息。
贰 广播的类型
Android系统提供了两种广播类型,有序广播和无序广播,开发者可根据需求为程序设置不同的广播类型。
- 无序广播:无序广播是完全异步执行,发送广播时所有监听这个广播的广播接收者都会接收到此消息,但接收的顺序不确定。
- 有序广播:按照接收者的优先级接收,只有一个广播接收者能接收消息,在此广播接收者中逻辑执行完毕后,才会继续传递。
- 局部广播
- 使用LocalBroadcastManager.sendBroadcast方法在同sender同一个app内部发送广播。 如果你不需要在不同的app之间发送广播,使用局部广播。这种广播的实现更加高效,不需要进程间通信,也不需要担心安全限制。
叁 优先级
- 数值越大,优先级越高。如果两个广播接收者的优先级相同,则先注册的广播接收者优先级高。
//动态注册MyReceiver广播
MyReceiver one = new MyReceiver ();
IntentFilter filter = new IntentFilter();
filter.setPriority(1000);
filter.addAction("Intercept_Stitch");
registerReceiver(one,filter);
肆 有序广播
有序广播,它的广播方法有两个:
-
第一个方法的形式为:
sendOrderedBroadcast(Intent, String)
- 第二个参数可以省略,如果省略,表示广播接收者无需某种权限即可接收,如果不省略,则广播接收者必须具有第二个参数所指定的权限方可接收该广播。第一个参数值intent中包含广播接收者的意图过滤器中对应的action。
-
第二个方法的形式为:
public abstract void sendOrderedBroadcast (Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
- 该方法的前两个参数同上个方法,第三个参数表示最后一个必须接收到广播的接收者,第四个参数用于指定调度第三个接收者的线程,如果为null,表示所在上下文的主线程;
initialCode
结果码的初始值,通常为Activity.RESULT_OK
.
initialData
结果数据的初始值,通常为null
.
initialExtras
附加结果的初始值,通常为null
.
- 该方法的前两个参数同上个方法,第三个参数表示最后一个必须接收到广播的接收者,第四个参数用于指定调度第三个接收者的线程,如果为null,表示所在上下文的主线程;
4.1 中断广播
- 广播接收者如果希望中断广播,可以调用
abortBroadcast ()
来标记所接收的有序广播不再传递下去,如果sendOrderedBroadcast
中指定了最后接收者的话,该广播还会再传递给该最后接收者。 - 如果想取消中断广播,执行
clearAbortBroadcast ()
4.2 获取结果状态和数据
通过调用getResultCode ()
,可以获取上一个接收者传递过来的结果码;
通过调用getResultData ()
,可以获取上一个接收者传递过来的结果数据,通常为null
;
通过调用getResultExtras (boolean makeMap)
,可以获取到上一个接收者传递过来的附加数据,参数如果为true
,表示如果没有传递来的附加数据,会自动创建一个空的Map
,参数如果为false
,表示如果没有传递过来的附加数据,只返回null,不会创建新的Map
4.3 设置结果状态和数据
通过调用setResult (int code, String data, Bundle extras)
,改变有序广播中的结果码、结果数据和附加结果;
通过调用setResultCode (int code)
设置结果码,该参数通常为RESULT_CANCELED
和 RESULT_OK
;
通过调用setResultData (String data)
,改变广播的结果数据;
通过调用setResultExtras (Bundle extras)
会取代广播中原有的附加数据
4.4 判断是否为有序广播
调用isOrderedBroadcast ()
判断收到的广播是否是顺序广播
伍 通过权限来限制广播
- 使用权限可以限制广播发送到某些app集合,既可以限制发送者也可以限制接收者。
5.1 发送添加权限
- 当调用
sendBroadcast(Intent, String)
或者sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
的时候,可以指定一个权限参数。只有在manifest中已经获得该权限的接收者可以接收到该广播。 - 例如:
sendBroadcast(new Intent("com.example.NOTIFY"),Manifest.permission.SEND_SMS);
- 为了接收该广播,接收者必须需要获取权限:
//指定一个存在的系统权限,也可以使用<permission>自定义一个权限 <uses-permission android:name="android.permission.SEND_SMS"/>
- 注意:当app在安装到系统里的时候,自定义权限会被注册。自定义权限必须在app安装以后才能使用。
5.2 接收添加权限
- 当注册一个广播接收器的时候,你指定了一个权限参数,( 或者使用
registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
或者在manifest的<receiver>
标签中),那么只有那些在manifest
中使用<uses-permission>
来获取该权限的广播者采用向接收者发送广播意图。 - 假设广播接收者manifest定义如下:
<receiver android:name=".MyBroadcastReceiver" android:permission="android.permission.SEND_SMS"> <intent-filter> <action android:name="android.intent.action.AIRPLANE_MODE"/> </intent-filter> </receiver>
- 或者在MainActivity中注册广播接收者:
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );
- 为了向接收器发送广播,发送app必须如下获取权限:
<uses-permission android:name="android.permission.SEND_SMS"/>
陆 重要题目
- 简述广播机制的实现过程
- 广播接收者通过Binder机制在AMS(Activity Manager Service)中进行注册
- 广播发送者通过Binder机制向AMS发送广播。
- AMS查找符合相应条件(IntentFilter/Permission)的广播接收者(BroadcastReceiver),将广播发送到相应的消息循环队列中。
- 执行消息循环时获取到此广播,会回调广播接收者(BroadcastReceiver)中的onReceive()方法并在该方法中进行相关处理。
- 简述有序广播和无须广播的区别
- 发送广播时,使用的方法不同。有序广播使用
sendOrderedBroadcast()
发送广播,而无序广播使用sendBroadcast()
方法发送广播。 - 广播接收者执行的顺序。
- 有序广播的接收者是顺序执行的。有序广播按照广播接收者声明的优先级别被依次接收。当在高级别的广播接收者逻辑执行完毕之后,广播才会继续传递。当优先级相同时,先注册的广播接受者优先执行。
- 无序广播是完全异步执行的。当发送无序广播时,所有监听这个广播的广播接收者都会接收到此广播消息,但接收和执行的顺序不确定。
- 拦截广播:有序广播的接收者可拦截广播。如果优先级较高的广播接收者将广播终止,那么广播将不再向后传递。而无序广播则不能被拦截。
- 效率:有序广播的效率比无序广播低。
- 发送广播时,使用的方法不同。有序广播使用
- abortBroadcast:通过该方法可以终止有序广播
- 在清单文件中注册了NEW_OUTGOING_CALL,代码中获取到广播事件的方法是( ).
A、getAction()
B、getActionCall()
C、getMethod()
D、getOutCall()
- 解析:
- 在代码中获取广播事件的方法是使用广播接收器(BroadcastReceiver)来处理广播事件。当接收到广播事件时,广播接收器的onReceive()方法会被调用,并且可以通过Intent参数来获取广播事件的相关信息。在处理NEW_OUTGOING_CALL广播事件时,可以通过Intent的getAction()方法来获取广播事件的动作(Action)。例如:
//通过intent.getAction()方法获取广播事件的动作,并将其与"android.intent.action.NEW_OUTGOING_CALL"进行比较, //以判断是否接收到了NEW_OUTGOING_CALL广播事件 public class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals("android.intent.action.NEW_OUTGOING_CALL")) { // 处理NEW_OUTGOING_CALL广播事件 } } }
- 关于短信拦截的广播事件说法正确的是( ).
A、监听用户的短信到来的广播事件在高版本ADT里该事件找不到了
B、需要注册 权限
C、在国内国外注册这样的广播事件方式不一样
D、以上说法都正确 - 常驻型广播是当应用程序关闭后,如果接收到其他应用程序发出的广播,那么该程序会自动重新启动。
- 在清单文件中,注册广播时使用的节点是( C)。
A、<Activity>
B、<Broadcast>
C、<receiver>
D、<broadcastreceiver>
- 在清单文件中注册广播时使用的节点是
<receiver>
。<receiver>
节点用于声明一个广播接收器(BroadcastReceiver
),用于接收和处理广播事件。在<receiver>
节点中,可以指定广播接收器的类名、优先级、过滤器等属性。
- 在清单文件中注册广播时使用的节点是
- 对于一些特殊的广播事件,比如屏幕锁屏和解锁,对于这样的广播事件,需要采用动态代码的方式进行注册,在清单文件注册不生效
- 注册外拨电话的广播事件对应的action是
android_intent.action.NEW_OUTGOING_CALL
- 下面关于静态注册广播接收者中Exported属性的描述,正确的是()。
A、广播接收者是否可以由系统实例化
B、是否接收当前程序之外的广播
C、创建广播接收者名称
D、以上说法都不对 - 代码注册广播需要调用( registerReceiver() )方法,解除广播需要调用( unrigisterReceiver() )方法
- 注册广播有两种方式,常驻型广播与( 非常驻型广播 )
- 注册广播有两种方式,常驻型广播与非常驻型广播。- 常驻型广播(Sticky Broadcast):常驻型广播是指在广播发送后,即使没有注册的广播接收器,后续注册的广播接收器也能接收到该广播。常驻型广播可以通过
sendStickyBroadcast(Intent intent)
方法发送。这种广播适用于需要在广播发送后,后续注册的广播接收器也能接收到广播事件的场景。 - 非常驻型广播(Normal Broadcast):非常驻型广播是指在广播发送后,只有已经注册的广播接收器能接收到该广播。非常驻型广播通过
sendBroadcast(Intent intent)
方法发送。这种广播适用于只希望已经注册的广播接收器能接收到广播事件的场景。
- 常驻型广播(Sticky Broadcast):常驻型广播是指在广播发送后,即使没有注册的广播接收器,后续注册的广播接收器也能接收到该广播。常驻型广播可以通过
- 需要注意的是,常驻型广播可能会增加系统负担,因为即使没有注册的广播接收器,系统仍然会将广播事件保存在内存中,直到有广播接收器注册为止。因此,应谨慎使用常驻型广播,避免对系统性能产生不必要的影响。
- 手机重启对应的广播事件是( android.intent.action.BOOT_COMPLETED )
- 广播是一种运用在应用程序之间( 传递消息 )的机制
- 注册系统短信到来的广播事件需要加入的权限是( android.permission.RECEIVE_SMS )