广播机制做为android进程间通信的一个重要机制被广泛的使用。我承认已经到了滥用的地步。正因为如此,各方案公司甚至google都已经对它做修改限制,来达到控制大家滥用的目的。(这说明这个机制本身的设计还是很成功的,说明它对于使用者来说,简单、方便,耦合度低的特点)。
那么android是设计broadcast的这套机制的。我们来看一下大致的流程。
android的广播机制分为注册和接收两块。使用者将自己感兴趣的广播向系统注册,系统在接收到相应的广播后,会找到各个注册者,并调用onReceive。
看调用方式,以在activity中调用为例:
public class MainActivity extends Activity {
private static final String Tag="TEST";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter("com.test.broadcast");
registerReceiver(receiver, filter);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(receiver);
}
private BroadcastReceiver receiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Receive ....");
}
};
}
然后看Activity中是怎样处理registerReceiver(receiver, filter);的。发现Activity类中并没有直接实现该函数。再找它的父类ContextThemeWrapper,也没有,接着找ContextThemeWrapper的父类ContextWrapper:
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
调用了mBase的registerReceiver,mBase又是个什么东西呢?
它是一个ContextImpl ,为什么?
这要从launch一个android的应用说起,我把代码贴上来:
在ActivityThread.java中有:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
....
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
.....
而createBaseContextForActivity代码是这样的:
private Context createBaseContextForActivity(ActivityClientRecord r,
final Activity activity) {
ContextImpl appContext = new ContextImpl();
...
Context baseContext = appContext;
...
return baseContext;
}
Activity.java的attach函数:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attachBaseContext(context);
.
@Override protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
mBase = newBase;
}
所以,mBase是一个ContextImpl的实例。
这是套路!
我们来看Context,ContextThemeWrapper,ContextWrapper和ContextImpl这几个类之间的关系类图(公司限制不能上传图片或文件,所以或许有一天这张图片失效了):
再看套路之装饰模式:
是不是很相似的感觉!
这就是套路!
这里说一下android的命名,其实android的命名还是很统一的,基本上从类或文件的命名上,就能看出端倪来。XXXWrapper就说明了问题,这对于我们看android代码很有帮助,后续会陆续说到android命名来看相关的代码。我们不可能把整个android的代码都背下来,但是,如果我们掌握了规律,找起代码来就会快一些。
继续跟踪ContextImpl里的
@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());
}
转到registerReceiverInternal:
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;
}
}
mPackageInfo是一个LoadedApk的实例。看一下它的成员变量。
private final ActivityThread mActivityThread;
private final ApplicationInfo mApplicationInfo;
final String mPackageName;
private final String mAppDir;
private final String mResDir;
private final String[] mSharedLibraries;
private final String mDataDir;
private final String mLibDir;
private final File mDataDirFile;
private final ClassLoader mBaseClassLoader;
private final boolean mSecurityViolation;
private final boolean mIncludeCode;
private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
Resources mResources;
private ClassLoader mClassLoader;
private Application mApplication;
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
= new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
= new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
从它的成员变量看的出,这是个挺重要的类。尤其是成员变量ActivityThread mActivityThread。注意到mReceivers,看上去这个变量记录了应用的所有Receiver。
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
获得了主线程的handler.
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
这里的getReceiverDispatcher返回的是IIntentReceiver类型实例,Binder对象。而Binder用于IPC通信的,那么这个Binder对象要和谁进行IPC通信呢?应该是ActivityManagerService。
这个函数的实现:
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();
}
}
先从mReceivers中找rd,这里为空,所以就new 了一个ReceiverDispatcher,并将它放入mReceivers中记录下来。key是一个Context,这里指的就是我们的MainActiviy,所以通过一个activity可以找到对应的map,再通过BroadcastReceiver就可以找到相应的广播接收发布器ReceiverDispatcher了。(引:http://blog.csdn.net/luoshengyang/article/details/6737352)在新建广播接收发布器ReceiverDispatcher时,会在构造函数里面创建一个InnerReceiver实例,这是一个Binder对象,实现了IIntentReceiver接口,可以通过ReceiverDispatcher.getIIntentReceiver函数来获得,获得后就会把它传给ActivityManagerService,以便接收广播。在ReceiverDispatcher类的构造函数中,还会把传进来的Handle类型的参数activityThread保存下来,以便后面在分发广播的时候使用。
这样说来,ActivityManagerService就能找到对应的BroadcastReceiver,并且往对应的线程中发送消息了。而这个消息的响应函数应该就是BroadcastReceiver的onReceive函数了。
回到ContextImpl.registerReceiverInternal函数中,
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
调用了ActivityManagerNative的内部类ActivityManagerProxy.registerReceiver:
public Intent registerReceiver(IApplicationThread caller, String packageName,
IIntentReceiver receiver,
IntentFilter filter, String perm, int userId) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(packageName);
data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
filter.writeToParcel(data, 0);
data.writeString(perm);
data.writeInt(userId);
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
reply.readException();
Intent intent = null;
int haveIntent = reply.readInt();
if (haveIntent != 0) {
intent = Intent.CREATOR.createFromParcel(reply);
}
reply.recycle();
data.recycle();
return intent;
}
这里直接调用Binder驱动,说明这个过程在使用IPC通信。所以真正的执行体转移到远程对象去了。这里使用了代理模式,特征命名ActivityManagerProxy。实际的实现者是在远端的ActivityManagerService.
ActivityManagerService.registerReceiver:
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
...
ReceiverList rl
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
rl.app.receivers.add(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
...
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadast");
}
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
int N = allSticky.size();
for (int i=0; i<N; i++) {
Intent intent = (Intent)allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
mRegisteredReceivers.put(receiver.asBinder(), rl);将receiver记录下来,
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
这里将filter与receiver关联在了一起,然后记录下来:
mReceiverResolver.addFilter(bf);
到这里,整个注册过程完成。注册的信息由客户端调用最终被ActivityManagerService记录在两个成员变量mReceiverResolver和mRegisteredReceivers中。