种类:普通广播,系统广播,本地广播 ,粘性广播 。
正式因为静态注册耗电、占内存、不受程序生命周期影响,所以Google在Android 8.0上禁止大部分广播的静态注册——Android 8.0新特性-取消大部分静态注册广播。
原理篇
https://www.jianshu.com/p/bc5ffb349822
BroadcastReceiver的注册
Android系统中BroadcastReceiver的注册方式分为动态注册和静态注册两种。动态注册必须在程序运行期动态注册,其实际的注册动作由ContextImpl对象完成;静态注册则是在AndroidManifest.xml中声明的。在基础篇中提到过,因为静态注册耗电、占内存、不受程序生命周期影响,所以Google在Android 8.0上禁止了大部分广播的静态注册,以此来减少耗电、增加待机时间、节省内存空间、提升性能。
动态注册过程源码分析
Activity是通过Context类的registerReceiver()方法进行动态注册广播监听的。Context是一个抽象类,它是应用端和AMS、WMS等系统服务进行通信的接口,Activity、Service和Application都是继承它的子类。Context的实现类是ContextImpl,也就是说注册时最终调用到的是ContextImpl中的registerReceiver方法。下面将以registerReceiver为入口一步步分析广播是如何动态注册和接收的。
ContextImpl中的registerReceiver方法最终会调用本类的私有方法registerReceiverInternal。在这个方法里面主要做了两件事情,一件是通过LoadedApk类提供的方法获得IIntentReceiver的实例,另一件是通过ActivityManagerService.registerReceiver方法把广播注册到AMS中。
接下来跳转到LoadedApk和ActivityManagerService中看看在IIntentReceiver实例化和广播注册到AMS的时候具体做了什么事情。
- 客户端(LoadedApk)
当Activity中有新的BroadcastReceiver被注册,LoadedApk就会为他生成一个ReceiverDispatcher实例,然后把Context、BroadcastReceiver和ReceiverDispatcher三者的关系存储到关系映射表中。其中,在ReceiverDispatcher的构造方法中生成了IIntentReceiver类的实例,并可以通过ReceiverDispatcher.getIIntentReceiver方法获得。
LoadedApk的相关源码如下:
服务端(ActivityManagerService)
AMS在收到客户端广播注册请求时,会把提供服务的IIntentReceivers接口、ReceiverList和BroadcastFilter的映射关系存储到映射关系表中。同时,把BroadcastFilter存储到广播解析器IntentResolver中。
静态注册过程源码分析
BroadcastReceiver静态注册指的是在AndroidManifest.xml中声明的接收器,在系统启动的时候,会由PMS去解析。当AMS调用PMS的接口来查询广播注册的时候,PMS会查询记录并且返回给AMS。
广播的发送和接收
以最简单普通广播为例,直接跳到Context的实现类ContextImpl的sendBroadcast方法。从源码看sendBroadcast里面基本没干什么事,直接去调用的AMS的broadcastIntent方法。
AMS中的broadcastIntent方法里面也没干什么,直接调用本类的broadcastIntentLocked方法(broadcastIntentLocked方法有600多行代码,OMG)。
接下来看一下BroadcastRecord类中的scheduleBroadcastsLocked方法是如何把广播发送到对应的BroadcastReceiver中的。
在ActivityThread的scheduleRegisteredReceiver方法中执行了IIntentReceiver.performReceive方法。