Android广播机制一

  广播机制做为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中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值