Broadcast 分析 --- 之一

1, 基本概念

广播(Broadcast):顾名思义,就是一处发生事情,多处得到通知后分别进行处理。和观察者模式有相似之处。一般Activity发送广播。

 

1.1  receiver

receiver接收广播,还分为动态和静态两种。动态receiver是在运行期通过调用registerReceiver()注册的,而静态receiver则是在

AndroidManifest.xml中声明的。一般使用动态广播,原因可以研究一下。有事广播已经发出去了,包含接受静态广播的进程还没

有起来,因为在手机开机时注册。比如,刚开机时,phone进程还没有开始运行,别人就已经打电话来了,这时候先运行phone进程,

然后在进程里接收广播并进行处理。

1.2 Broadcast

依据Broadcast的作用,可以将广播分为三种:

1,一般广播,所有注册该广播的receiver都处于相同的位置,同时接受并且处理。

2,有序广播,所有receiver只能按照一定的优先级顺序,依次接收并且处理;不仅如此,前面的receiver不仅可以将额外的信息

塞入广播还可以终止广播。

   静态广播: AndroidManifest.xml, <intent-filter>android:priority属性

   动态广播: IntentFilter对象的setPriority()方法来设置优先级

  数值越大表示优先级越高,取值范围为-1000到1000.

3,粘性广播: 可以保证“在广播递送时尚未注册的receiver”,一旦日后注册进系统,就能够马上接到“错过”的sticky广播。

这是一种很神奇的广播,我觉得关机时的来电(开机后,收到错过电话的通知)应该就是这种广播。

 

静态广播大都是有序广播。

2,注册广播关键代码解析

2.1 类图


2.2 流程图

动态广播注册的流程图如下,

这只是动态注册的类图和流程图。

2.3 代码解析

ContextImpl的registerReceiver方法如下,

首先看看getReceiverDispatcher方法,

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;
        }
    }

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;
            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的定义,是一个表中表,

private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> 
mReceivers = new ArrayMap<Context, ArrayMap<BroadcastReceiver, 
LoadedApk.ReceiverDispatcher>>();

在Android的架构里,应用进程里是用LoadedApk来对应一个apk的,进程里加载了多少个apk,就会有多少LoadedApk。

每个LoadedApk里会有一张“关于本apk动态注册的所有receiver”的哈希表mReceivers。该表的key项是我们比较熟悉的

Context,也就是说可以是Activity、Service或Application。而value项则是另一张“子哈希表”。这是个“表中表”的形式。

言下之意就是,每个Context(比如一个activity),是可以注册多个receiver的,这个很好理解。mReceivers里的“

子哈希表”的key值为BroadcastReceiver,value项为ReceiverDispatcher,示意图如下:


然后看看跨进程调用到AMS中的registerReceiver方法,

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
        enforceNotIsolatedCaller("registerReceiver");
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        int callingUid;
        int callingPid;
        synchronized(this) {
           •••
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                String action = actions.next();
                for (int id : userIds) {
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    if (stickies != null) {
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }

        synchronized (this) {
            •••
            ReceiverList rl = 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 broadcast");
            }
            mReceiverResolver.addFilter(bf);
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);

                final int stickyCount = allSticky.size();
                for (int i = 0; i < stickyCount; i++) {
                    Intent intent = allSticky.get(i);
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                          null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }

注意这句 mReceiverResolver . addFilter (bf);后面动态广播查询的时候会调用此查询。

registerReceiver()函数的filter参数指明了用户对哪些intent感兴趣。对同一个BroadcastReceiver对象来说,可以注册

多个感兴趣的filter,就好像声明静态receiver时,也可以为一个receiver编写多个<intent-filter>一样。这些IntentFilter信息

会汇总到AMS的mRegisteredReceivers表中。每个客户端的ReceiverDispatcher,会对应AMS端的一个ReceiverList。

将上文的ReceiverDispatcher和ReceiverList通过mRegisteredReceivers一一对应。

138.final  HashMap<IBinder,ReceiverList> mRegisteredReceivers= new HashMap<>();

一个receiver可以包含多个不同的IntentFilter,可以被Context注册多次。因此

ReceiverList里面保存的是相同receiver的不同IntentFilter(过滤器)。所以最终的对应关系为


2.4 静态receiver

静态receiver是在AndroidManifest.xml文件中声明,该信息会在系统启动时,由PackageManagerService解析并记录下来。

静态receiver并不是是常驻内存的,常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。

该类向外界提供了queryIntentReceivers()函数,该函数可以返回一个List<ResolveInfo>列表。主要目的就是当系统发出一个

广播时,该类必须能够得出有多少静态receiver对这个广播感兴趣,而且知道这些receiver的详细信息。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值