广播是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); } @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 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 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,如要想要查看的话就需要科学上网到上面的这个网址