Android广播机制分析

博客源址:Android广播机制分析

以下转载

1.1. 广播简介


        Android 广播与生活中的广播概念不同,它是指系统中产生事件后的通知。Android 广播不关心接收者是否收到处理或者如何处理广播,可以说是一种单向的通知。
        Android 通过 BraodcastReceiver 来监听系统发出的广播,不同的 BraodcastReceiver 通过设置不同的 fliter 来区分监听广播的类型。有些广播的监听需要相应的权限。

1.2. 注册广播


        BraodcastReceiver 必须经过注册才能具有监听功能,注册的方式有两种:

1.2.1. 静态注册


        通过在 AndroidManifest.xml 中注册对应的 receiver,并设置要监听的 action


        其中 MyReceiver 为继承 BroadcastReceiver 的类,重写了 onReceiver 方法,并在 onReceiver方法中对广播进行处理。<intent-filter>标签设置过滤器,接收指定 action 广播。静态注册方式的特点:不管改应用程序是否处于活动状态,都会进行监听。action 可以为自定义 action,也可以是系统自带的 action。


1.2.2. 动态注册


动态注册是在程序中对 BroadcastReceiver 完成监听注册
[java]  view plain  copy
 print ?
  1. MyReceiver receiver = new MyReceiver();  
  2. //创建过滤器,并指定 action,使之用于接收同 action 的广播  
  3. IntentFilter filter = new IntentFilter("MyReceiver_Action");  
  4. //注册广播接收器  
  5. registerReceiver(receiver, filter);  
  6. 在 activity 中注册广播,必须在 activity 结束时注销广播,一般在 onStart 中注册  
  7. BroadcastReceiver,在 onStop 中取消 BroadcastReceiver,广播接收器跟随 Activity 的生命周期  
  8. //注销广播接收器  
  9. unregisterReceiver(receiver);  


1.3. 生命周期


        BroadcastReceiver 生命周期只有 8 秒左右,如果在 onReceive()内做超过 8 秒内的事情,就会报ANR(Application Not Response)程序无响应的错误信息。它的生命周期为从回调 onReceive()方法开始到该方法返回结果后结束。因此,如果要在收到广播后做耗时操作,最好放到 service 中去做,子线程也不好,当子线程未结束的时候,BroadcastReceiver 已经销毁。


1.4. 发送广播


1.4.1. Android 中发送广播的三种形式


        广播被分为三种不同的类型:“普通广播(Normal broadcasts)”、“有序广播(Ordered broadcasts)”和“粘性广播(Sticky broadcast)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有广播接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播 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 广播


假设有如下优先级的 5 个接收器
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. 只能动态接受广播源码分析


有些广播,我们无法用静态接收器接收,比如 ACTION_SCREEN_ON,当屏幕被点亮的时候系统发送此广播。
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. 1void com.android.server.PowerManagerService.initInThread()  
  2. 2. Java 代码  
  3. 3void initInThread() {  
  4. 4. „„  
  5. 5. mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);  
  6. 6. mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);  
  7. 7. mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);  
  8. 8. mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);  
  9. 9. „„  
  10. 10. }  

        Intent 中都设置了 Intent.FLAG_RECEIVER_REGISTERED_ONLY,所以,如果要接收,必须动态注册广播接收器 ACTION_SCREEN_OFF 也是如此。

1.6.1. 关于 FLAG_RECEIVER_REGISTERED_ONLY 的说明


public static final int
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(电池电量发生变化的时候,系统发送此广播)该广播就是这样
void com.android.server.BatteryService.sendIntent()
[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. Java 代码  
  2. 1private final void sendIntent() {  
  3. 2//  
  4. 3. Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);  
  5. 4. intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY  
  6. 5.  
  7. Pack up the values and broadcast them to everyone  
  8. 6.  
  9. 7. }  

1.7. 广播注册过程分析


1.7.1. 静态注册 Receiver 的流程


        静态 receiver 的注册是由 PackageManagerService 开机的时候负责初始 PMS 在开机的时候会对系统一些目录逐个扫描,解析 apk 文件。静态广播接收器就是在 PMS 做这件事情的时候顺便处理的。
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 的流程


        动态注册最终会调用到 AMS 中的 registerReceiver 函数,最终所有动态注册的 receiver 都保存到 AMS 的成员变量 mReceiverResolver 中。静态广播和动态广播如何注册的,我们已经全部分析完了。静态广播是 PackageManagerService负责,保存到其成员变量 mReceivers 中,动态广播是 ActivityManagerService 负责,保存到其成员变量 mReceiverResolver 中。

1.8. 广播发送过程分析


1.8.1. 分析


Context 中的 sendBroadCast 函数的实现是在 ContextImpl 中,和发送广播相关的有如下六个函数:

[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. void android.app.ContextImpl.sendBroadcast(Intent intent)  
  2. void android.app.ContextImpl.sendBroadcast(Intent intent, String receiverPermission)  
  3. void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission)  
  4. void android.app.ContextImpl.sendOrderedBroadcast(Intent intent, String receiverPermission,  
  5. BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,  
  6. Bundle initialExtras)  
  7. void android.app.ContextImpl.sendStickyBroadcast(Intent intent)  
  8. void android.app.ContextImpl.sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver  
  9. resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle  
  10. initialExtras)  
        可以分为 3 组:1 普通广播;2 Ordered 广播;3 Sticky 广播。不论哪种,最后都会由 AMS 处理

        如果是非 ordered 广播,那么 mParallelBroadcasts 将存储所有动态接收器,然后合并的时候,mParallelBroadcasts 设置为 null,所以不会合并到 receivers 中,如果是 ordered 广播,那么mParallelBroadcasts 将合并到 receivers 中,然后,不管是哪种广播,最后都是调用scheduleBroadcastsLocked 继续处理,最终到 processNextBroadcast 函数上。广播是否有序,即通过 Boolean 变量 ordered 进行设置。

1.8.2. 总结


        发送过程情况分为两种(scheduleBroadcastsLocked),ordered 广播和非 ordered 广播、非ordered 广播。先处理动接收器,然后处理静态接收器 ordered 广播同时处理动态接收器和静态接收器先将动态接收器与静态接收器合并,保持着与优先级相同的顺序,优先级高的在前面,否则顺序不变。静态接收器与动态接收器优先级相同的话,动态接收器在前。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 休眠唤醒机制是指在设备进入休眠(睡眠)状态后,如何触发设备的唤醒操作。在 Android 系统中,休眠是指将设备的 CPU、屏幕和其他硬件组件进入低功耗状态,以节省电量。休眠状态下,应用程序的运行和响应暂时被挂起,但系统仍然会保持一些必要的功能在后台运行。 当设备进入休眠状态后,有两种方式可以唤醒设备。第一种方式是通过外部事件唤醒,例如用户按下了电源键或其他物理按键、插入了充电器、接收到电话等。此时,系统会接收到相应的事件信号,并触发设备的唤醒操作。第二种方式是通过定时器唤醒,也就是设备设置了一个特定的时间,在到达该时间时自动唤醒设备。 在 Android 系统中,可以使用的休眠唤醒机制有以下几种: 1. AlarmManager:通过定时器来唤醒设备。可以使用 setExact() 方法设置精确的唤醒时间,或者使用 setWindow() 方法设置一个时间范围,在该范围内唤醒设备。 2. BroadcastReceiver:可以注册一个广播接收器,在接收到指定的广播消息时,唤醒设备。常用的广播消息有BOOT_COMPLETED(设备启动完成时)、ACTION_SCREEN_ON(屏幕亮起时)、ACTION_USER_PRESENT(屏幕解锁时)等。 3. WakeLock:可以通过申请 WakeLock 来保持设备唤醒状态,直到释放 WakeLock 或达到指定的时间。常用的 WakeLock 参数有 PARTIAL_WAKE_LOCK(保持 CPU 运转)、SCREEN_DIM_WAKE_LOCK(保持屏幕亮起时)等。 总的来说,Android 休眠唤醒机制提供了多种方式来唤醒设备,开发者可以根据自己的需求选择适合的方式。但需要注意的是,过度使用休眠唤醒机制会增加设备耗电量,降低系统性能,因此需要合理使用并进行优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值