广播大的氛围两类:动态和静态,细分为普通广播,系统广播,有序广播,局部广播。
静态广播:在清单文件中配置
动态广播:使用Java 代码
优先级:动态大于静态
普通广播:
<receiver android:name=".receiver.NetWorkStateReceiver">
<intent-filter android:priority="100"> //优先级
<action android:name="com.mainActivity.broadcast"/>//是定义的的action
</intent-filter>
</receiver>
动态广播:
//发送关闭 Intent intent = new Intent();
intent.setAction("com.mainActivity.broadcast");
getActivity().sendBroadcast(intent);
//或者用 sendOrderedBroadcast(intent,null),第二个参数 Permission 如果设置null了标识所有广播均可以接收到
IntentFilter intentFilter = new IntentFilter("com.mainActivity.broadcast");
intentFilter.setPriority(1000);//这是动态设置优先级,可以不设置或者设置小写,1000代表优先级最高
broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context , Intent intent) { //intent.getAction()就能得到自己想要的唯一标识action了 } } ;IntentFilter:
IntentFilter中具有和Intent对应的用于过滤Action,Data和Category的字段,而在BroadcastReceiver中体现出的就是action,一个隐式Intent要想被一个组件处理,检查 Action 尽管一个Intent只可以设置一个Action,但一个Intentfilter可以持有一个或多个Action用于过滤,到达的Intent只需要匹配其中一个Action即可。 深入思考:如果一个Intentfilter没有设置Action的值,那么,任何一个Intent都不会被通过;反之,如果一个Intent对象没有设置Action值,那么它能通过所有的Intentfilter的Action检查。
也就是说action的匹配规则是Intent中的action必须能够和过滤规则中的action字符串完全一样。一个过滤中可以有多个action,Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功,Intent只有一个action而IntentFilter可以设置多个action。
intent setAction添加一个action,系统内部也会定义多个action
public @NonNull Intent setAction(@Nullable String action) {
mAction = action != null ? action.intern() : null;
return this;
intentFilter.addAction
public IntentFilter(String action) {
mPriority = 0;
mActions = new ArrayList<String>();
addAction(action);
}
public final void addAction(String action) {
if (!mActions.contains(action)) {
mActions.add(action.intern());
}
}
发送原理
Broadcast的发送是以AMS为中心,通过AMS的分发将消息分发到对应的接收器中。并且这个过程是通过IPC Binder 来完成的。
发送流程图
发送过程
Step 1.ContextWrapper.sendBroadcast()
Intent intent = new Intent("...");
sendBroadcast(intent);
Intent intent = new Intent("...");
sendBroadcast(intent);
这是第一步,发送广播的操作非常简单,生成一个Intent,然后调用sendBroadcast发送就可以了。ContextWrapper的调用其实是一个代理类,实际调用是在ContextImpl。
Step 2.ContextImpl.sendBroadcast()
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(...);
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(...);
在ContextImpl才是发送广播的起点,首先Intent会调用prepareToLeaveProcess()准备离开现有进程,然后调用AMS的broadcastIntent()开始发送过程。
Step 3.ActivityManagerNative.broadcastIntent()
这个类就是一个代理,这个函数的职责很简单,将传过来的参数打包到Parcel,然后通过Binder将数据传到AMS里。
Step 4.ActivityManagerService.broadcastIntent()
int res = broadcastIntentLocked(...)
int res = broadcastIntentLocked(...)
此函数就是解析一下传进来的数据,然后调用AMS的broadcastIntentLocked进行下一步。
Step 5.ActivityManagerService.broadcastIntentLocked()
这个函数比较长,我们一段一段来看。
Part 1:
intent = new Intent(intent);
...
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
if (...) {
registeredReceivers = mReceiverResolver.queryIntent(intent,...);
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,...);
}
intent = new Intent(intent);
...
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
if (...) {
registeredReceivers = mReceiverResolver.queryIntent(intent,...);
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,...);
}
这一段是根据Intent的值找出相应接受的广播接收器。因为AMS会把注册的广播接收器保存到mReceiverResolver变量里。
Part 2:
final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
这一段就是判断是否要替换之前的intent。
Part 3:
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(...);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(...);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
这里首先会通过broadcastQueueForIntent()从AMS的全局变量mFgBroadcastQueue或mBgBroadcastQueue中获取一个队列,里面保存着所有Broadcast对象。然后通过获取的参数新创建一块BroadcastRecord块,将它添加到队列里面去。接下来我们看scheduleBroadcastsLocked()的过程。
Step 6.BroadcastQueue.scheduleBroadcastsLocked()
if (mBroadcastsScheduled) {return;}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
if (mBroadcastsScheduled) {return;}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
这里的mBroadcastsScheduled表示AMS当前是不是正在处理其它广播,如果是的话,这里就先不处理直接返回了,保证所有广播串行处理。因为是通过消息的方式来发送,所以广播的发送和处理是异步的。成员变量mHandler是一个AMS内部的BroadcastQueue定义的Handler类变量,把一个空的类型为BROADCAST_INTENT_MSG的消息放到队列里。
Step 7.BroadcastQueue.handleMessage()
case BROADCAST_INTENT_MSG:
processNextBroadcast(true);
case BROADCAST_INTENT_MSG:
processNextBroadcast(true);
很简单,又是通过processNextBroadcast()来处理下一条广播。
Step 8.BroadcastQueue.processNextBroadcast()
mBroadcastsScheduled = false;
...
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
final int N = r.receivers.size();
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
}
mBroadcastsScheduled = false;
...
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
final int N = r.receivers.size();
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
}
这里就是分发的核心了,首先将mBroadcastsScheduled设为false是让下一条消息能发送,接着循环mParallelBroadcasts的size将里面的广播记录块取出来,因为里面包含了目标target,通过deliverToRegisteredReceiverLocked将它发送给订阅了的接收器。
Step 9.BroadcastQueue.deliverToRegisteredReceiverLocked()
if (filter.requiredPermission != null) {
...
skip = true;
}
...
if (!skip) {
performReceiveLocked(...);
}
if (filter.requiredPermission != null) {
...
skip = true;
}
...
if (!skip) {
performReceiveLocked(...);
}
这一段做了很多个判断,都是在检查广播发送和接受的权限判断,如果不通过这直接跳过。在通过判断后再调用performReceiveLocked执行发送操作。
Step 10.BroadcastQueue.performReceiveLocked()
首先来看下这个函数的参数:
performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser)
performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser)
这里首先判断通过注册进来的广播是什么,因为例子中是通过activity注册的,这里的app参数就是代表activity的进程记录块,receiver这是注册时传给AMS的Binder对象。在调用后会通过:app.thread.scheduleRegisteredReceiver()函数把广播分发给activity。
Step 11.ApplicationThreadNative.scheduleRegisteredReceiver()
这里也很简单,做一个打包通过binder分发而已。
Step 12.ApplicationThread.scheduleRegisteredReceiver()
传进来的第一个参数是IIntentReceiver receiver,其实际类型是定义在LoadedApk类的内部类ReceiverDispatcher里面的一个内部类InnerReceiver,调用performReceive函数来执行。
Step 13.LoadedApk.ReceiverDispatcher.InnerReceiver.performReceive()
LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
rd.performReceive();
LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
rd.performReceive();
这里又是一个转折,调用LoadedApk.ReceiverDispatcher类的performReceive()来执行。
Step 14.LoadedApk.ReceiverDispatcher.performReceive()
final Handler mActivityThread;
...
Args args = new Args()
if (!mActivityThread.post(args)) {}
final Handler mActivityThread;
...
Args args = new Args()
if (!mActivityThread.post(args)) {}
在ReceiverDispatcher类里mActivityThread的类型是一个handler,它是前面MainActivity注册广播接收器时,从ActivityThread取得的。这里ReceiverDispatcher借助这个Handler,把这个广播以消息的形式放到MainActivity所在的这个ActivityThread的消息队列中去。而Args是ReceiverDispatcher的一个内部类,继承自Runnable类。
Step 15.Hanlder.post
post的作用就是把消息放在消息队列中,然后就返回,这个消息最终会在传进来的Runnable类型的参数的run成员函数中进行处理。
Step 16.LoadedApk.ReceiverDispatcher.Args.run
final BroadcastReceiver receiver = mReceiver;
final Intent intent = mCurIntent;
...
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
final BroadcastReceiver receiver = mReceiver;
final Intent intent = mCurIntent;
...
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
mReceiver是ReceiverDispatcher类的成员变量,它就是MainActivity注册广播接收器时创建的BroadcastReceiver实例。在这里就能够通过receiver将广播分发到处理的地方了。
Step 17.BroadcastReceiver.onReceive
最后就是定义在自己类里的onReceive被调用,整个过程到此结束。
总结
最后我们将整个过程来总结一下:
- 第一阶段:Step 1 ~ Step 7:通过自己的sendBroadcast把一个广播通过Binder进程间通信机制发送给AMS,AMS根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去。
- 第二阶段:Step 8 ~ Step 15:AMS在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进MainActivity所在的线程的消息队列中去。
- 第三阶段:Step 16 ~ Step 17:ReceiverDispatcher的内部类Args在MainActivity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive函数进行处理。