Android组件体系之BroadcastReceiver小结
1、常见分类
BroadCastReceiver,按注册方式可以分为静态广播接收器和动态广播接收器。
静态广播接收器:不受程序是否启动的约束,当应用程序关闭之后,还是可以接收到广播(一般广播接收器的生命周期是和当前活动的生命周期保持同步)。
动态广播接收器:可以自由的控制注册和取消,有很大的灵活性。但是只能在程序启动之后才能收到广播。
对于广播(Broadcast),则可以分为普通广播和有序广播。
其中普通广播不在意顺序,各进程的广播接收器基本上可以同时收到这个广播。而有序广播,系统会根据接收者声明的优先级按顺序逐个接收处理,先收到有序广播的接收器,可以对该有序广播进行修改或者截断。
静态注册的广播接收器,在接收广播时,系统自动按有序广播的方式来串行处理(原因是进程的创建不能并发),此类接收器收到广播的先后顺序,和接收器所在package名称有关,或者说,和PMS扫描顺序有关。
动态注册的广播接收器,如果接收普通广播,接收器收到广播的顺序则和注册顺序有关。在所有普通广播里面,动态注册的广播接收器,相对于静态注册的广播接收器,会优先收到普通广播。
同优先级的动态有序广播,注册顺序影响广播的接收顺序;同优先级的静态有序广播,扫描顺序影响其接收顺序。
除了前面提到的这些,还有一种相对不太常用的:LocalBroadcastManager方式注册的应用内广播接收器,只能通过LocalBroadcastManager动态注册。
2、注册过程简述
动态注册的广播接收器,主要通过ContextImpl、LoadedApk,再调用AMS的registerReceiver方法完成。
静态注册的广播接收器,是在系统启动时,由PMS解析apk文件并记录receivers信息,然后AMS调用PMS的接口来查询intent匹配信息,再完成广播注册过程。
3、发送和接收过程简述
发送广播,主要通过ContextImpl、LoadedApk、AMS、ActivityThread完成。接收广播时,先是在AMS里面处理,找到接收者然后加到一个队列,再向对应的线程发送广播消息。
从Android O开始,系统对静态注册的广播接收器添加了限制,必须指定广播接收器所在包名才可以发送,或者使用Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND这个flag,但该标志是隐藏的,如果必须使用静态广播接收器、又不能指定包名(例如发送一对多的广播),则可以使用该标志的具体数值0x01000000。
4、安全性
可以使用权限提升广播接收的安全性。如果接收器定义了权限,发送的广播需要对应声明权限才能发送;反之一样,不然收不到。整体上,有以下几种情况:
- 指定发送方,发送者有权限才能发此广播;
- 指定接收方,接收者声明权限才能收到该广播;
- 同时指定发送方和接收方(很少使用)。
无论是哪种情况,都涉及到自定义权限,所以都需要在AndroidManifest.xml中声明对应的权限。
对于第一种情况(接收器定义权限来限制发送方),如果是动态广播接收器,可以在注册时通过registerReceiver传入该权限。静态广播接收器则是在AndroidManifest.xml里面,定义广播接收器的地方,添加android:permission属性,将该属性设为自定义权限。
5、 onReceive()中的Context入参
这里的入参为context变量,其实例的具体类型,可以分为下面几种情况。
1)、静态注册的广播接收器
这种情况下,入参是android.app.ReceiverRestrictedContext类型,不能用来启动Activity、弹出AlertDialog(除了系统应用且Dialog类型是SYSTEM_ALERT_WINDOW类型)。
2)、动态注册的广播接收器
具体又分两种情况:
a) 在Activity里面注册广播接收器。此时onReceive的入参context就是注册广播接收器的Activty对象。
由于此时入参contex为Activity的Context对象,可用于启动Activity、弹出AlertDialog。
但考虑到onReceive()方法在主线程中,该方法需要在10秒内执行完毕,生命周期很短。如果弹出的对话框需要等待用户响应,就需要考虑对话框的管理问题。常用的做法是,将其放在Service里面管理,在Service启动的时候注册一个动态广播接收器,Service停止的时候注销之。
b) 在Service里面注册广播接收器。此时onReceive的入参context对应该Service对象,和Service是否跨进程无关。这种情况下的Context不能启动Activity,有若干限制。
这两种情况可以统一为,onReceive的入参context就是调用registerReceiver的组件的Context。
其他还有LocalBroadcastManager注册的应用内广播接收器。其onReceive中的context是Application的Context。
(相关完整且成体系的文章,可参见本人原创的开源电子书《Android系统与性能优化》,地址:https://github.com/carylake/androidnotes)
最新文章
- 嵌入式Linux驱动学习之路(二十四)Nor Flash驱动程序
- Jquery揭秘系列:谈谈bind,one,live,delegate事件及实现
- 【HOW】如何允许编辑用户配置文件属性
- Linux SAMBA Practical
- js for 循环中的 变量问题。
- Lintcode: Product of Array Exclude Itself
- P235 实战练习(集合类2)、摇奖程序和验证码(修改版)
- EventBus学习
- android 解释dp,px,pt,sp单位
- Strust2最基本使用
- BCM wifi分析
- Go语言Web框架gwk介绍 3
- nginx反向代理cas-server之2:生成证书,centOS下使用openssl生成CA证书(根证书、server证书、client证书)
- 一条sql执行过长的时间,你如何优化,从哪些方面?
- php之sphinx
- ajax参数传递之[HttpGet]/[HttpPost]/[HttpPut]/[HttpDelete]请求
- node连接myslq
- Xcode - 打开工程,提示No Scheme解决
- posix_memalign详细解释(转)——自定义对齐大小的内存分配函数
- 外部引用CSS中 link与@import的区别
热门文章
- 【黑客基础】Windows PowerShell 脚本学习(上)
- OSI案例详解+ARP+DNS
- OC循环方法推荐-块循环遍历(比for循环好用)
- Python中的Tcp协议的应用之Tcp服务端程序开发
- 转:关于java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication的解决
- JavaEE基础(02):Servlet核心API用法详解
- 【如何让代码变“高级”(二)】-这样操作值得一波666(Java Stream)(这么有趣)
- Cisco 7200 路由 PPPOE 拨号详解
- CNN卷积神经网络的构建
- 获取iOS设备的型号