1.1 广播简介
Android广播与生活中的广播概念不同,它是指系统中产生时间后的通知。Android广播不关心接收者是否收到处理或者如何处理广播,可以说是一种单向的通知。
Android通过BroadcastReceiver来监听系统发出的广播。不同的BroadcastReceiver通过设置不同的fliter来区分监听广播的类型。有些广播的监听需要相应的权限。
1.2 注册广播
BroadcastReceiver必须经过注册才能具有监听功能,注册的方式有两种:
1.2.1静态注册
通过在AndroidManifest.xml中注册对应的receiver,并设置要监听的action
其中MyReceiver为继承BroadcastReceiver的类,重写了onReceiver方法,并在onReceiver方法中对广播进行处理。<intent-filter>
标签设置过滤器,接收指定action广播。静态注册方式的特点:不管该应用程序是否处于活动状态,都会进行监听。action可以为自定义action,也可以是系统自带的action。
1.2.2动态注册
动态注册是在程序中对BroadcastReceiver完成监听注册
- MyReceiver receiver = new MyReceiver();
- //创建过滤器,并指定 action,使之用于接收同 action 的广播
- IntentFilter filter = new IntentFilter("MyReceiver_Action");
- //注册广播接收器
- registerReceiver(receiver, filter);
- 在 activity 中注册广播,必须在 activity 结束时注销广播,一般在 onStart 中注册
- BroadcastReceiver,在 onStop 中取消 BroadcastReceiver,广播接收器跟随 Activity 的生命周期
- //注销广播接收器
- unregisterReceiver(receiver);
1.4 发送广播
广播被分为三种不同的类型:“普通广播(Normal broadcasts)”、“有序广播(Ordered broadcasts)”和“粘性广播(Sticky broadcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有广播接收者接收到,消息传递的效率比较高,但缺点是:
接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播,然而有序广播室按照接收者声明的优先级别(声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000(其实最大可以为int最大值即:2147483647))。也可以调用IntentFilter对象的setPriority()进行设置,被接收者依次接收广播。如:A 的级别高于 B,B 的级别高于 C,那么,广播先传给 A,再传给 B,最后传给 C。A 得到广播后,可以往广播里存入数据,当广播传给 B 时,B 可以从广播中得到 A 存入的数据。Context.sendBroadcast()发送的是普通广播,所有订阅者都有机会获得并进行处理。
Context.sendOrderedBroadcast()发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播。BroadcastReceiver.abortBroadcast()如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将处理结果存放进广播 Intent,然后传给下一个接收者。Context.sendStickyBroadcast()是发送粘性广播,使用这个 api需要权限 android.Manifest.permission.BROADCAST_STICKY,粘性广播的特点是 Intent 会一直保留到广播事件结束,而这种广播也没有所谓的 8 秒限制,即上文所讲,如果 onReceive 方法执行时间太长,超过 8 秒的时候系统会将这个广播置为可以干掉的 candidate,一旦系统资源不够的时候,就会干掉这个广播而让它不执行。
1.5. 广播优先级
1.5.1. 基本原则
接收无序广播的接收器也一样可以设置优先级的
动态注册广播优先级高于静态注册广播
同等优先级的动态接收器,先注册的先接收
同等优先级的静态接收器,接收广播的顺序与 String[] java.io.File.list()顺序一致
Ps:这里有一点需要注意的是,同等优先级的静态接收器的接收顺序具有不确定性,原因就是File.list()的方法返回的顺序具有不确定性,如果需要查看某接收器的接收顺序,最好是试验大量的 apk 名。
1.5.2. ordered 广播
1.动态 A(优先级=1)
2.动态 B(优先级=2)
3.动态 C(优先级=2)
4.静态 D(优先级=1)
5.静态 E(优先级=2)
并且 B 先于 C 注册
那么实际接收顺序应为
B C E A D
也就是说,如果静态接收器的优先级高于动态接收器的优先级,那么还是静态接收器先接收到广播(比如接收 SMS 广播)
1.5.3. 非 ordered 广播
1.6. 只能动态接受广播源码分析
- 1. void com.android.server.PowerManagerService.initInThread()
- 2. Java 代码
- 3. void initInThread() {
- 4. „„
- 5. mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
- 6. mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- 7. mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
- 8. mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- 9. „„
- 10. }
Intent 中都设置了 Intent.FLAG_RECEIVER_REGISTERED_ONLY,所以,如果要接收,必须动态注册广播接收器 ACTION_SCREEN_OFF 也是如此。
1.6.1. 关于 FLAG_RECEIVER_REGISTERED_ONLY 的说明
FLAG_RECEIVER_REGISTERED_ONLY
Added in API level 1
If set, when sending a broadcast only registered receivers will be called -- no
BroadcastReceiver components will be launched.
Constant Value: 1073741824 (0x40000000)
ACTION_BATTERY_CHANGED(电池电量发生变化的时候,系统发送此广播)该广播就是这样
- Java 代码
- 1. private final void sendIntent() {
- 2. //
- 3. Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
- 4. intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
- 5.
- Pack up the values and broadcast them to everyone
- 6.
- 7. }
1.7. 广播注册过程分析
1.7.1. 静态注册 Receiver 的流程
PMS 会解析 apk 的 manifest 文件,查找这里注册的 receiver,然后加载到内存中。
PMS 初始化扫描目录的顺序:
system/framework
system/app
vendor/app
data/appd
rm/app-private
我们看到了 PMS 如何在初始化的时候如何解析 manifest 并把其中的 element 存放到内存中的其中receiver 保存到了 owner 的成员变量 receivers 中,owner 的类型是
android.content.pm.PackageParser.Package 也就是说 scanPackageLI 返回结果就是已经包含了manifest 信息的 Package 对象。
1.7.2. 动态注册 Receiver 的流程
1.8. 广播发送过程分析
1.8.1. 分析
- void android.app.ContextImpl.sendBroadcast(Intent intent)
- void android.app.ContextImpl.sendBroadcast(Intent intent, String receiverPermission)
- void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission)
- void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission,
- BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
- Bundle initialExtras)
- void android.app.ContextImpl.sendStickyBroadcast(Intent intent)
- void android.app.ContextImpl.sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver
- resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle
- initialExtras)
1.8.2. 总结