广播是Android的四大组件之一,在Android的源码中也大量存在并使用了它,此外它也是一种常见的跨进程通信方式,由此可见它的重要性。

这里就对广播的底层实现进行一个解析

本文中间包含了广播的代码细节,可以直接查看最后的“一句话总结”

分类

首先,广播可以分为动态和静态注册两种方式。

动态注册的含义也就是在代码中注册广播,程序关闭是无效,在同等优先级下它会比静态注册的广播先调用

静态注册是指在AndroidManifest文件中注册的广播,由于APK在安装时静态注册的广播的信息会被PMS扫描并被添加到系统的表中,因此它在程序关闭时依然有效,例如开机自启就是属于检测自启的动作,如果发生该广播,就会启动自身的APP

上面的两种分类属于大分类,又可以将他们细分为普通广播、粘性广播、有序广播等等。

有序广播
使用sendOrderedBroadcast发送广播,高优先级的会先收到广播,然后由它决定是否处理、下传或者是终止该广播的传递

粘性广播
使用sendStickyBroadcast发送广播。如果发送时当前系统中并没有对应的广播接收器,那么它仍然会驻留在系统中,一旦有对应的广播接收器注册,那么就立即发送给它。

而如果它发送了多条,多条都没人接收的话怎么办呢?系统就会保存最后一条广播,因为这样就可以避免粘性广播在系统中的冗余。使用removeStickyBroadcast可以移除该Intent。

其实广播本来就是为了解耦,而粘性广播则更加解耦,因为接收方甚至可以完全不存在,这肯定是它的一个优势

生命周期

onReceive是在主线程中被调用的,因此要注意不能在onReceive中出现耗时操作。如果一定要有,那么就最好开一个线程或者是交给service去处理

此外,只有当接受到了广播后,BroadcastReceiver这个类才会被实例化,不管它是动态还是静态注册的。
当内存不足时,receiver也会被系统回收掉,所以如果有长时间的任务,最好交给其他的来做,例如service

基本使用

动态注册

  • 创建一个BroadcastReceiver
  • 创建IntentFilter,并指定Action
  • registerReceiver(receivcer, intentFilter)
  • sendBroadcast(new Intent(“haha”));
  • unregisterReceiver(receiver);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(MainActivity.this, "Receive", Toast.LENGTH_SHORT).show();
}
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("haha");

registerReceiver(receiver, intentFilter);

sendBroadcast(new Intent("haha"));
unregisterReceiver(receiver);

这样也就完成了一个广播的动态注册,但是需要注册的一点,广播注册之后一定要记得取消,一般是在onDestory中取消,其他的根据实际情况取消也是可以的。

静态注册
直接在AndroidManifest文件中添加

1
2
3
4
5
6
<receiver android:name=".MyReceiver">  
<intent-filter>
<action android:name="android.intent.action.MY_BROADCAST"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>

实现原理

我们从动态注册的广播入手

1
registerReceiver(receiver, intentFilter);

这一行代码就是注册广播,那它做了什么呢?点进去看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}

@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return mBase.registerReceiver(receiver, filter, broadcastPermission,
scheduler);
}

/** @hide */
@Override
public Intent registerReceiverAsUser(
BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
scheduler);
}

这里我们就进入到了ContextWrapper文件中,而第三个方法我们暂时不用管他,因为它是被@hide标记了的,只关心前面两个方法。而前面的两个方法又分别调用了mBase也就是一个Context中对应的方法

对于ContextWarapper来说,它只是Context的一个代理类,也就是说它是为Context服务的,一些小工作也就是不是核心的东西Context都是交给它来做的。而一些核心工作最终又返还给Context来处理。这样就可以在一定程度上实现解耦以及工作职责的分离,Context完全不需要考虑那些它本来不需要也不想知道的事情。

1
2
3
4
5
6
/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context. Can be subclassed to modify behavior without changing
* the original Context.
*/
public class ContextWrapper extends Context {

Context:

1
public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,IntentFilter filter);

我们的Context也是一个抽象类,它的具体实现是在ContextImpl中的。Context里面实际上就是一些资源的获取的工作,它还有几个子类就是Activity,Application和Service

ContextImpl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}

@Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, user.getIdentifier(),
filter, broadcastPermission, scheduler, getOuterContext());
}

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}

好了,这下就一目了然,我们只有两个参数的registerReceiver最终也是调用了四个参数的方法,而后面的两个参数broadcastPermission以及Handler直接被设置为空。

最终的一个工作都是交给registerReceiverInternal来做的。首当其冲的就是这个IIntentReceiver类,这个类是做什么的呢?它实际上就是一个binder实体,通过这个东西我们就可以实现跨进程的信息传递了.它是由ReceiveDispather来管理的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}

最后,它返回了一个ActivityManagerNative.getDefault().registerReceiver()方法,继续跟进可以知道ActivityManagerNative.getDefault()实际上就是获取一个唯一的IActivityManager实例,它是一个单例模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
return gDefault.get();
}

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};

public abstract class Singleton<T> {
private T mInstance;

protected abstract T create();

public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}

那么它返回的IActivityManager到底是谁呢?其实就是ActivityManagerService,简称AMS。

1
2
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

在我的博客杂谈——Android从启动到程序运行发生的事情中详解介绍到了AMS的功能,它实际上就是一个管理器,管理着非常多的东西,在系统中的作用极大。所有的Activity操作都是由Activity向他发出一个申请,它进行处理(比如向Zygote发送命令创建一个新的ActivityThread)之后返给Activity,Activity再交给Instrumentation来继续完成(例如生命周期的操作),而我们的注册广播和解除注册广播也是交给它来完成的。

由于对应的代码有点长,这里就不贴出来了,只是总括一下它以及sendBrodcast和unregister里面完成的东西。

一句话总结

当一个广播进行发送时,它会被发送到AMS中并由它完成广播的传递,而AMS利用Binder机制,也就是上面的IIntentReceiver将他们传递到各个应用进程,应用进程再调用recevier的onReceive()的方法,这也就完成了一次广播的传递。

而对于注册广播来说,存在一个LoadApk对象,这个对象里面会包含关于本APK动态注册的所有receiver的哈希表,每当我们注册一个receiver,那么他就会被添加进入这个LoadApk的哈希表中。同时在我们注册的时候会记录用户对哪些receiver感兴趣,同一个Receiver可以注册多个IntentFilter,同样的也会使用一个ReceiverList来存储所有的IntentFilter信息。

所以当一个消息发来的时候,AMS会合并静态注册的表以及动态注册的表,同等优先级下动态注册的receiver在靠前的位置。匹配IntentFilter并查找对应的receiver哈希表,找到该Receiver,并利用Binder机制进行分发。

最后再安利一个网址,https://android.googlesource.com/?format=HTML,有很多代码Google处于安全性并没有直接暴露给开发者,所以在AndroidStudio中并不能查看到,例如上面的IIntentReceiver,如要想要查看的话就需要科学上网到上面的这个网址