BroadcastReceiver的工作过程
1.广播的注册过程 2.广播的发送和接收过程
回顾广播的使用方法
1.定义广播接收者
继承BroadcastReceiver并重写onReceive方法
2.注册广播接收者
静态注册
在AndroidManifest文件中静态注册
动态注册(需要在合适的时机解注册)
3.通过send方法发送广播
广播注册、发送和接受的大致流程图
广播的注册过程
静态注册
在应用安装时由系统自动完成注册,具体来说是PMS(PackageManagerService)来完成整个注册过程,其他三大组件也是在应用安装时由PMS解析并注册的。
动态注册
从ContextWrapper的registerReceiver方法开始,它把注册过程交给了ContextImpl来完成
它又把注册过程交给registerReceiverInternal方法
registerReceiverInternal方法实现如下
系统首先从mPackageInfo获取IIntentReceiver对象rd,然后再采用跨进程的方式向AMS发送广播注册的请求。不采用BroadcastReceiver是因为上述注册过程是一个进程间通信的过程,而它作为一个安卓组件时不能直接跨进程传递的,所以要通过IIntentReceiver来中转。IIntentReceiver必须是一个Binder接口,它的具体实现是LoadApk.ReceiverDispatcher.InnerReceiver,ReceiveDispatcher的内部同时保存了BroadcastReceiver和InnerReceiver,这样当接收到广播时,ReceiverDispatcher可以很方便地调用BroadcaseReceiver的onReceive方法.可以发现BroadcastReceiver的这个过程和Service的实现原理类似,Service也有一个ServiceDispatcher的类,并且其内部类InnerConnection也是一个Binder接口,同样也是为了进程间通信。下面看一下ReceiveDispatcher的getIIntentReceiver的实现
getReceiveDispatcher方法重新创建了一个ReceiverDispatcher对象并将其保存的InnerReceiver对象作为返回值返回,其中InnerReceiver对象和BroadcastReceiver都是在ReceiverDispatcher的构造方法中被保存起来的。
注册广播的真正实现过程是在AMS中,所以我们需要看一下AMS的registerReceiver方法(太长,只看核心代码)
最终把远程的InnerReceiver对象以及IntentFilter对象存储起来,这样子整个广播的注册过程就完成了
广播的发送和接收过程
当通过send方法来发送广播时,AMS会查找出匹配的广播接收者并将广播发送给它们处理。广播的发送有几种类型:普通广播 有序广播 粘性广播(已经弃用),但他们流程是类似的,因此这里只分析普通广播
广播的发送
开始于ContextWrapper的sendBroadcast方法,不用Context中的send方法是因为Context的send方法是一个抽象方法。ContextWrapper同样把事情交给ContextImpl处理
它向AMS发起了一个异步请求用于发送广播,下面之间看AMS的broadcastIntent方法
它调用了broadcastIntentLocked方法(很长,截取部分了解)
这表示默认情况下广播不会发送给已经停止的应用
两个标签控制广播是否要对处于停止状态的应用起作用
FLAG_INCLUDE_STOPPED_PACKAGES
表示包含已经停止的应用,这个时候广播会发送给已经停止的应用
FLAG_EXCLUDE_STOPPED_PACKAGES
表示不包含已经停止的应用,这个时候广播不会发送给已经停止的应用
继续上面的方法解析
它会根据intent-filiter查找出匹配的广播接收者并经过一系列的条件过滤,最终会将满足条件的广播接收者添加到BroadcastQueue中,接着BroadcastQueue就会将广播发送给相应的广播接收者
看一下BroadcastQueue中广播的发送过程
它发送了一个BROADCAST_INTENT_MSG类型的消息,BroadcastQueue收到消息后会调用processNextBroadcast方法,BroadcastQueue的processNextBroadcast方法对普通广播的处理如下
无序广播存储在mParallelBroadcasts中,系统会遍历mParalledBroadcasts并将其中的广播发送给它们所有的接收者,具体的发送过程通过deliverToRegisteredReceiverLocked方法实现,它将一个广播发送给一个特定的接收者,它内部调用了performReceiveLocked方法来完成具体的发送过程
由于接收广播会调起应用程序,因此app.thread不为null,这里的app.thread仍然是ApplicationThread。它调用了scheduleRegisteredReceiver方法
IIntentrReceiver的performReceive方法会调用LoadedApk.ReceiverDispatcher的performReceive方法
它创建了一个Args对象并用mActivityThread的post方法来执行Args中的逻辑,而Args实现了Runnable接口。mActivityThread是一个Hnalder,它其实就是ActivityThread中的mH,mH就是ActivityThread的内部类H。
在Args的run方法中
这个时候Broadcast的onReceive方法被执行,也就是说应用已经收到广播了,同时onReceive是在广播接收者的主线程中被调用的。