广播的动态注册过程

广播的动态注册过程

广播的注册分为清单文件中的静态注册和代码中的动态注册两种形式,这里分析下动态注册的过程,下面先看下动态注册的使用代码:

//创建BroadcastReceiver对象
BroadcastReceiver receiver = new BroadcastReceiver() {
	     	 @Override
	         public void onReceive(Context context, Intent intent) {
	             //TODO 处理接收到的广播消息
	
	         }
	     };

//注册广播
IntentFilter filter = new IntentFilter();
filter.addAction("cn.znh.receiver.filter.action");
registerReceiver(receiver, filter);

在使用代码动态注册广播的时候会调用registerReceiver方法进行注册,跟到这个方法里面会发现,又调用了父类ContextWrapper的registerReceiver方法:

Context mBase;

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

ContextWrapper的registerReceiver方法里又调用了mBase的方法,mBase的具体实现类型是ContextImpl(可以查看《Context的创建过程》),那就看下ContextImpl的registerReceiver方法:

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {

	//注释1
    return registerReceiver(receiver, filter, null, null);
}

在注释1处又调用了它的重载方法:

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {

	//注释2
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext(), 0);
}

在注释2处调用了registerReceiverInternal方法:

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
           IntentFilter filter, String broadcastPermission,
           Handler scheduler, Context context, int flags) {

		//注释3
       IIntentReceiver rd = null;
       
       if (receiver != null) {
           if (mPackageInfo != null && context != null) {
               if (scheduler == null) {
                   scheduler = mMainThread.getHandler();
               }

			   //注释4
               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 {

		   //注释5 调用了AMS的registerReceiver方法
           final Intent intent = ActivityManager.getService().registerReceiver(
                   mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                   broadcastPermission, userId, flags);
           if (intent != null) {
               intent.setExtrasClassLoader(getClassLoader());
               intent.prepareToEnterProcess();
           }
           return intent;
       } catch (RemoteException e) {
           throw e.rethrowFromSystemServer();
       }
}

注释3处的rd是IIntentReceiver类型的,IIntentReceiver是个aidl接口,所以rd是支持跨进程通信的,由注释4可知rd对象是从mPackageInfo.getReceiverDispatcher方法中获取到的,mPackageInfo的类型是LoadedApk,看下源码:

 public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;

			//注释6
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            if (registered) {
                map = mReceivers.get(context);
                if (map != null) {
                    rd = map.get(r);
                }
            }
            if (rd == null) {
				//注释7
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    //注释8
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }

在注释6处创建了一个map集合,由注释8处可以知道存储的key就是我们自己注册的BroadcastReceiver对象,value是LoadedApk.ReceiverDispatcher对象(如果为空就在注释7处创建),ReceiverDispatcher是LoadedApk的一个静态内部类,看下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);
           mReceiver = receiver;
           mContext = context;
           mActivityThread = activityThread;
           mInstrumentation = instrumentation;
           mRegistered = registered;
           mLocation = new IntentReceiverLeaked(null);
           mLocation.fillInStackTrace();
 }

在ReceiverDispatcher构造方法里创建了一个IIntentReceiver对象,这个对象就是mPackageInfo.getReceiverDispatcher的返回值,它的具体实现是InnerReceiver,而InnerReceiver继承并实现了IIntentReceiver.Stub,所以InnerReceiver对象是支持跨进程通信的,同时也将我们自己的receiver对象赋值给了 mReceiver保存了起来,这样ReceiverDispatcher就同时拥有了本地的BroadcastReceiver对象和支持跨进程的InnerReceiver对象,这样就可以很方便的支配它们两个工作,需要跨进程的工作交由InnerReceiver对象完成,需要回调onReceiver方法时调用客户端定义的BroadcastReceiver对象的onReceiver方法。

回到ContextImpl中的registerReceiverInternal方法里,rd对象是可以跨进程的,这个对象被当作AMS的registerReceiver方法里的一个参数(注释5处),AMS跟App是两个独立的进程,所以ActivityManager.getService().registerReceiver是一个跨进程通信的一个过程,而我们自己的BroadcastReceiver对象是App进程中的一个组件不能直接进行跨进程传递,所以创建了一个和它相对应的可以跨进程传递的IIntentReceiver对象rd来完成进程间传递,下面继续跟踪到AMS的registerReceiver方法里,看看是怎么注册的:

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
          IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
          int flags) {
          ........................
          
           //注释9 保存IIntentReceiver对象
           mRegisteredReceivers.put(receiver.asBinder(), rl);
           
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                  permission, callingUid, userId, instantApp, visibleToInstantApps);
          if (rl.containsFilter(filter)) {
              Slog.w(TAG, "Receiver with filter " + filter
                      + " already registered for pid " + rl.pid
                      + ", callerPackage is " + callerPackage);
          } else {
              rl.add(bf);
              if (!bf.debugCheck()) {
                  Slog.w(TAG, "==> For Dynamic broadcast");
              }
              //注释10 保存IntentFilter对象
              mReceiverResolver.addFilter(bf);
          }
         ........................
}

在AMS的registerReceiver方法中,注释9处保存了IIntentReceiver对象信息,注释10处保存了IntentFilter对象信息,这样AMS就有了广播组件的所有信息,就可以处理后续的发送和接收事件了,这样就完成了广播的注册。关于广播的发送和接收流程放到下篇文章中进行总结梳理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值