android framework开发之广播broadcast源码分析2-千里马
Posted Android高级知识分享官
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android framework开发之广播broadcast源码分析2-千里马相关的知识,希望对你有一定的参考价值。
hi,上一节我们主要分析了broadcast的发送部分,本节我们来分析一下接受部分,即一般我们作为一个广播接受者是怎么一步步被AMS发送过来的信息的。
一般我们注册成为一个广播监听接受者都是调用Context.java中的如下方法:
public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
IntentFilter filter);
这里一样其实最后都会调用到ContextImpl.java中:
@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(), 0);
最后会调用到registerReceiverInternal方法:
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags)
IIntentReceiver rd = null;
if (receiver != null)
if (mPackageInfo != null && context != null)
//构造出IIntentReceiver
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
try
//调用 ActivityManager对应的registerReceiver方法来注册到AMS且把rd传递进去
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
return intent;
这里主要其实就分为2部分:
1、构造出一个IIntentReceiver对象
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
这里会调用到getReceiverDispatcher方法:
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;
//判断是否已经缓存了对应的IIntentReceiver对象
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();
这里应该比较容易看懂,就是简单的判断是否有缓存,没有就再进行构造,但是这里要注意哦,返回要求是IIntentReceiver类型,而new的是一个ReceiverDispatcher类型,那么这个IIntentReceiver是哪里构造来的呢?这里就要看ReceiverDispatcher构造源码了:
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered)
if (activityThread == null)
throw new NullPointerException("Handler must not be null");
mIIntentReceiver = new InnerReceiver(this, !registered);//这个地方new出来了这个InnerReceiver对象
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
mLocation.fillInStackTrace();
这里的
final static class InnerReceiver extends IIntentReceiver.Stub
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong)
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser)
//省略部分
这里最后发现InnerReceiver其实是实现了IIntentReceiver.Stub 这个跨进程对象的一个实体,也就是我们说的Binder的实现端,服务端,因为这里我们注册广播属于接受者,当然是由客户端调用到我们这端,所以当然就是服务端。
2、调用 ActivityManager对应的registerReceiver方法来注册到AMS且把rd传递进去
这里就是调用了:
ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
这个方法一看大家就应该知道最后会跨进程调用到AMS中:
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags)
//省略部分
synchronized (this)
//省略部分
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null)
//根据receiver创建出一个ReceiverList,为啥是个List?因为很有可能一个Receiver可能接受多个广播
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
//省略部分
mRegisteredReceivers.put(receiver.asBinder(), rl);
//省略部分
//构造出对应的BroadcastFilter,主要为了方便到时候发端方便寻找到这个接受端
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter))
else
rl.add(bf);//bf被添加到了对应的rl
mReceiverResolver.addFilter(bf);
//省略部分
这里其实就是在AMS中把广播的对应ReceiverList创建出来,而且与Filter进行映射好,这样广播接受者在AMS中的注册就算完成
总结图如下:
最后宣传一下课程:
[入门课,实战课,跨进程专题
ps需要学习深入framework课程和课程优惠
(可以加我qq:2102309716 优惠购买)
以上是关于android framework开发之广播broadcast源码分析2-千里马的主要内容,如果未能解决你的问题,请参考以下文章
android framework开发之广播broadcast源码分析2-千里马