美文网首页Android进阶笔记
Android进阶笔记-4. BroadcastReceiver

Android进阶笔记-4. BroadcastReceiver

作者: 今阳说 | 来源:发表于2022-01-11 18:58 被阅读0次

    关于BroadcastReceiver

    • BroadcastReceiver(广播接收者)是一个系统全局的监听器,用于监听系统全局的Broadcast广播消息,使用观察者模式,基于消息的发布/订阅事件模型;
    广播的分类
    1. 普通广播:开发者自身定义intent的广播;
    2. 系统广播:Android中内置的多个系统广播,每个广播都有特定的Intent - Filter;
    3. 有序广播:发送的广播被广播接收者按照priority属性值大小排序,priority相同的,动态注册的广播优先
    //发送有序广播
    val intent = Intent(ACTION_MY)
    intent.setPackage(packageName)
    sendOrderedBroadcast(intent, null)//第二个参数是一个与权限相关的字符串,这里传 null 就行了
    
    //拦截有序广播,广播被终止,以后不会有其他广播接收者再收到广播了
    class NetWorkChangeReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == ACTION_MY) {
                abortBroadcast()//表示这条广播截断,后面的广播接收器无法再接受到这条广播
                //本地广播不能调用abortBroadcast,报错Call while result is not pending
            }
        }
    }
    
    1. 本地广播:只在app内传播, 信息不会泄露,也不会被别人的广播干扰, 比全局广播更安全高效;
    2. 粘性广播:由于在Android5.0中已经失效,所以不建议使用;
    //添加权限:
    <user-permission android:name="android.permission.BROADCAST_STICKY"/>
    btn.setOnClickListener {
        val intent = Intent(ACTION_MY)
        sendStickyBroadcast(intent)
        btn_sendBroadcast_ACTION_MY.postDelayed({
            registerReceiver(netWorkChangeReceiver, intentFilter)
        }, 3000)
    }
    
    广播的注册方式
    • BroadcastReceiver的注册分为两种,分别是静态注册和动态注册;
    静态注册
    • 静态注册在应用安装时由PackageManagerService来完成注册过程, 当在系统注册一个BroadcastReceiver之后,每次系统以一个Intent的形式发布Broadcast的时候,系统都会创建与之对应的BroadcastReceiver广播接收者实例,并自动触发它的onReceive()方法,当onReceive()方法被执行完成之后,BroadcastReceiver的实例就会被销毁。
    • 注册方式:在AndroidManifest.xml里通过<receive>标签声明
    <receiver
        android:name=".activity.BootBroadcastReceiver"
        android:enabled="true" //标记允许系统启动
        android:exported="true" //能否接收其他App的发出的广播
        android:permission="string" //具有相应权限的广播发送者发送的广播才能被接收
        android:process="string" //可以指定独立的进程, 默认为app的进程
        android:priority="1000"> //设置优先级,必须是整数,默认是0, 范围是[-1000, 1000], 数字越大,优先级越高
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    
    动态注册
    • 动态注册则是用户手动创建BroadcastReceiver实例,调用registerReceiver进行注册,在不用时调用unregisterReceiver进行解绑,解绑后会销毁该实例;
    • 动态广播最好在Activity 的 onResume()注册、onPause()注销,因为动态广播有注册就必然得有注销,否则会导致内存泄露,而且重复注销也不允许
    val intentFilter = IntentFilter()
    intentFilter.addAction(ACTION_CONNECTIVITY_CHANGE)
    intentFilter.addAction(ACTION_MY)
    netWorkChangeReceiver = NetWorkChangeReceiver()
    intentFilter.priority = 1000
    registerReceiver(netWorkChangeReceiver, intentFilter)
    
    class NetWorkChangeReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == ACTION_CONNECTIVITY_CHANGE) {
                log("onReceive: 网络发生变化")
                log("netType:$NetworkUtils.getNetType()")
                if (NetworkUtils.isNetworkAvailable()) {
                    log("onReceive: 网络连接成功")
                } else {
                    log("onReceive: 网络连接失败")
                }
            }
        }
    }
    

    注册: registerReceiver

    • 动态注册需要调用registerReceiver方法,它的实现在ContextWrapper中
    @Override
    public Intent registerReceiver(@Nullable BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }
    
    • mBase 指的是什么呢?在上一篇Android进阶笔记-3. Service 启动过程 & 绑定过程中我们说过,ActivityThread启动Activity时会调用performLaunchActivity创建Activity的上下文环境,将ContextImpl赋值给ContextWrapper的成员变量mBase,因此mBase具体指向就是ContextImpl;
    • 那么来看一下ContextImpl的registerReceiver方法
    @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) {
            //如果LoadedApk类型的mPackageInfo不等于null并且context不等null,
            //就通过getReceiverDispatcher获取IIntentReceiver对象,否则new一个
            //IIntentReceiver是一个Binder接口,用于进行跨进程的通信,它的具体实现在LoadedApk.ReceiverDispatcher.InnerReceiver
            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 {
            //调用AMS的registerReceiverWithFeature方法
            final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
                    mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,
                    filter, broadcastPermission, userId, flags);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    
    • ActivityManagerService.registerReceiverWithFeature
    public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
                String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
                String permission, int userId, int flags) {
        ...
        synchronized(this) {
            ...
            //根据IntentFilter得到actions列表
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }
    
            // 根据actions列表和userIds(userIds可以理解为应用程序的uid)得到所有的粘性广播的intent
            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);
                        }
                    }
                }
            }
        }
    
        //将这些粘性广播的intent存入到allSticky列表, 可以看出粘性广播是存储在AMS中的
        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                if (instantApp &&
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);
                }
            }
        }
    
        // The first sticky in the list is returned directly back to the client.
        Intent sticky = allSticky != null ? allSticky.get(0) : null;
        if (receiver == null) {
            return sticky;
        }
    
        synchronized (this) {
            ...
            //获取ReceiverList列表,ReceiverList继承自ArrayList,用来存储广播接收者
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                //ReceiverList列表为空则new一个
                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并传入上面的ReceiverList,BroadcastFilter用来描述注册的广播接收者
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                ...
            } else {
                rl.add(bf);//通过add方法将bf添加到ReceiverList中
                ...
                //将bf添加到mReceiverResolver中
                //这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了
                mReceiverResolver.addFilter(bf);
            }
    
            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            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, null, -1, -1, false, null, null, OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1, false,
                            false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }
    
            return sticky;
        }
    }
    

    发送:sendBroadcast

    • 同样的,发送需要调用在ContextWrapper中的sendBroadcast方法
    @Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }
    
    • 最终实现在mBase:ContextImpl的sendBroadcast方法
    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
                    false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    
    • 最终会调用AMS的broadcastIntentWithFeature
     public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);//验证广播是否合法
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            try {
                return broadcastIntentLocked(callerApp,
                        callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                        requiredPermissions, appOp, bOptions, serialized, sticky,
                        callingPid, callingUid, callingUid, callingPid, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    }
    
    • 上面最终调用了broadcastIntentLocked方法,这个方法很长主要是对intent的一些操作和
    final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
                @Nullable String callerFeatureId, Intent intent, String resolvedType,
                IIntentReceiver resultTo, int resultCode, String resultData,
                Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
                boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
                int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
                @Nullable int[] broadcastWhitelist) {
        intent = new Intent(intent);
        //不去匹配停止运行的组件
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
        // FLAG_RECEIVER_BOOT_UPGRADE标志是系统升级的
        if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
            // 添加后只有动态注册的广播接收者能收到广播,这是因为在系统启动过程中,PackageManagerService可能还未启动,
            // 此时AMS是无法获得静态注册的广播接收者的
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        }
    
        ...
        final String action = intent.getAction();
        BroadcastOptions brOptions = null;
        if (bOptions != null) {
            ...//组装Bundle bOptions中的数据
        }
        ...
        if (action != null) {
            //判断各种action的情况
        }
    
        if (sticky) {
            //粘性广播的处理
        }
    
        List receivers = null;//静态广播接收器列表
        List<BroadcastFilter> registeredReceivers = null;//动态广播接收器列表
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            //由于静态注册的广播都保存在PMS中的mReceivers中了,
            //所以到PMS中找到所有静态注册的目标广播接收者,并保存在列表receivers中
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        }
        // 没有指定接收者组件名
        if (intent.getComponent() == null) {
            if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
                ...
            } else {
                // 由于动态注册的广播都存放在AMS的mReceiverResolver中了,
                // 所以在mReceiverResolver中查找动态注册的目标广播接收者,并保存在registeredReceivers列表中
                registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false, userId);
                ...
            }
        }
        ...
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        //如果不是有序的,使用registeredReceivers创建BroadcastRecord,并调用scheduleBroadcastsLocked
        if (!ordered && NR > 0) {
            //判断要发送的广播是前台广播还是后台广播并返回对应的广播队列
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                    callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts, timeoutExempt);
            //根据r到queue中的无序调度队列中查找是否存在与intent描述一致的广播,存在则替换并返回true
            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
            //replaced为true,说明不需要在无序广播调度队列中增加新的广播转发任务
            //否者就把r所描述的广播转发任务放在BroadcastQueue类中的mParallelBroadcasts无序调度队列中
            //重新调度这个队列中的广播转发任务,从这里可以看出动态注册的广播接收者比静态注册的广播接收者优先接收到无序广播
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
    
        // Merge into one list.
        int ir = 0;
        if (receivers != null) {
            ...
            //广播接收者按照优先级高低存储在receivers列表中
            // 这里动态注册广播合并的是有序的,因为无序动态广播处理中NR最后被赋值为0了
            while (it < NT && ir < NR) {
                ...
                // 如果动态注册广播接收者优先级大于等于静态广播接收者,则把动态注册的广播接收者插入到当前位置,
                // 静态注册的广播接收者后移,这说明同优先级动态注册的先于静态注册的接收到广播
                if (curr.getPriority() >= curt.priority) {
                    // Insert this broadcast record into the final list.
                    receivers.add(it, curr);
                    ir++;
                    curr = null;
                    it++;
                    NT++;
                } else {
                    // Skip to the next ResolveInfo in the final list.
                    it++;
                    curt = null;
                }
            }
        }
        // 把优先级低于所有静态注册广播接收者的动态广播接收者都追加到receivers列表中的末尾
        while (ir < NR) {
            if (receivers == null) {
                receivers = new ArrayList();
            }
            receivers.add(registeredReceivers.get(ir));
            ir++;
        }
        ...
        //下面的逻辑和上面差不多
        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                    callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts, timeoutExempt);
    
            final BroadcastRecord oldRecord =
                    replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
            if (oldRecord != null) {
                // Replaced, fire the result-to receiver.
                if (oldRecord.resultTo != null) {
                    final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
                    try {
                        oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                                oldRecord.intent,
                                Activity.RESULT_CANCELED, null, null,
                                false, false, oldRecord.userId);
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Failure ["
                                + queue.mQueueName + "] sending broadcast result of "
                                + intent, e);
    
                    }
                }
            } else {
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        } else {
            // There was nobody interested in the broadcast, but we still want to record
            // that it happened.
            if (intent.getComponent() == null && intent.getPackage() == null
                    && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                // This was an implicit broadcast... let's record it for posterity.
                addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
            }
        }
        return ActivityManager.BROADCAST_SUCCESS;
    }
    
    • 上面代码中会调用BroadcastQueue中的scheduleBroadcastsLocked方法将intent所描述的广播转发给目标广播接收者处理
    public void scheduleBroadcastsLocked() {
        if (mBroadcastsScheduled) {//标记是否已经向消息队列发送了一个类型为BROADCAST_INTENT_MSG消息
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
    
    • mHandler是BroadcastQueue类的内部类BroadcastHandler的实例
    private final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }
    
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    //处理广播的转发任务
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    //处理广播超时的操作,报ANR异常
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }
    
    • processNextBroadcast对无序广播和有序广播分别进行处理,来将广播转发给各目标广播接收者处理
    final void processNextBroadcast(boolean fromMsg) {
        synchronized (mService) {
            processNextBroadcastLocked(fromMsg, false);
        }
    }
    
    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;
        ...
        //是否是从handleMessage中调用的该方法
        if (fromMsg) {
            //表示前面发送到消息队列中的BROADCAST_INTENT_MSG消息已经被处理了
            mBroadcastsScheduled = false;
        }
        //循环处理保存在无序广播调度队列mParallelBroadcasts中的广播转发任务
        while (mParallelBroadcasts.size() > 0) {
            //获取mParallelBroadcasts中保存的第一个广播转发任务r,并移出队列
            r = mParallelBroadcasts.remove(0);
            ...
            for (int i=0; i<N; i++) {
                Object target = r.receivers.get(i);
                //遍历循环将无序广播发送给每一个目标广播接收者(动态注册的)
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }
            //添加r到历史队列中
            addBroadcastToHistoryLocked(r);
        }
        ...
        boolean looped = false;
        do {
            ...
            //循环在有序广播调度队列mOrderedBroadcasts(动态有序、所有静态)中找到下一个需要处理的广播转发任务
        } while (r == null);
        ...
        //处理动态有序广播接收者, 动态注册广播接收者是BroadcastFilter类型的
        if (nextReceiver instanceof BroadcastFilter) {
            ...
            return;
        }
    
        //r所描述的广播转发任务的下一个目标广播接收者不是BroadcastFilter类型的,
        //那就说明是一个静态注册的广播接收者,静态注册的广播接收者是ResolveInfo类型的,这里直接强转
        ResolveInfo info =
            (ResolveInfo)nextReceiver;
        ComponentName component = new ComponentName(
                info.activityInfo.applicationInfo.packageName,
                info.activityInfo.name);
        ...
        //判断静态注册的广播接收者所运行在的应用程序进程是否已经启动起来
        if (app != null && app.thread != null && !app.killed) {
            try {
                app.addPackage(info.activityInfo.packageName,
                        info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
                maybeAddAllowBackgroundActivityStartsToken(app, r);
                //如果已经启动,则直接将广播发送给它处理
                processCurBroadcastLocked(r, app, skipOomAdj);
                return;
            } catch...
        }
    
        // 调用startProcessLocked方法启动这个应用程序进程
        if ((r.curApp=mService.startProcessLocked(targetProcess,
                info.activityInfo.applicationInfo, true,
                r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                new HostingRecord("broadcast", r.curComponent),
                isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
                (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                        == null) {
            logBroadcastReceiverDiscardLocked(r);
            finishReceiverLocked(r, r.resultCode, r.resultData,
                    r.resultExtras, r.resultAbort, false);
            //如果进程启动失败,继续发送给r所描述的广播转发任务的下一个目标广播接收者处理
            scheduleBroadcastsLocked();
            r.state = BroadcastRecord.IDLE;
            return;
        }
        //如果成功启动进程,则保存r和recIdx,表示正在等待r所描述的广播转发任务的
        //下一个目标广播接收者所在的应用程序进程启动起来
        maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
        mPendingBroadcast = r;
        mPendingBroadcastRecvIndex = recIdx;
    }
    
    • 假设r所描述的广播转发任务的下一个目标广播接收者是一个动态注册的广播接收者,无论无序还是有序都就会调用deliverToRegisteredReceiverLocked方法进行处理
    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
        ...//省略各种权限检查
        if (ordered) {
            //如果是有序的
        }
        try {
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                if (ordered) {
                    skipReceiverLocked(r);
                }
            } else {
                ...
                //将r所描述的广播转发给filter所描述的目标广播接收者处理
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
                ...
            }
            if (ordered) {
                r.state = BroadcastRecord.CALL_DONE_RECEIVE;
            }
        } catch ...
    }
    
    • 对于无序广播通过了权限的检查,则会调用performReceiveLocked方法
    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser)
            throws RemoteException {
        if (app != null) {
            if (app.thread != null) {
                try {
                    //如果广播接收者所在的应用程序进程存在并且正在运行
                    //用广播接收者所在的应用程序进程来接收广播,这里app.thread指的是ApplicationThread
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
                } catch...
            } else {
                // Application has died. Receiver doesn't exist.
                throw new RemoteException("app.thread must not be null");
            }
        } else {
            //否者直接调用与它关联的一个IIntentReceiver对象的Binder代理对象的performReceive方法
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }
    
    • 如果广播接收者所在的应用程序进程存在并且正在运行用广播接收者所在的应用程序进程来接收广播,这里app.thread指的是ApplicationThread; 下面就看一下ActivityThread的内部类ApplicationThread的scheduleRegisteredReceiver方法
    public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
            int resultCode, String dataStr, Bundle extras, boolean ordered,
            boolean sticky, int sendingUser, int processState) throws RemoteException {
        updateProcessState(processState, false);
        //调用了IIntentReceiver类型的对象receiver的performReceive方法
        receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                sticky, sendingUser);
    }
    
    • 上面调用了IIntentReceiver类型的对象receiver的performReceive方法,实现receiver的类为LoadedApk.ReceiverDispatcher.InnerReceiver,代码如下
    @Override
    public void performReceive(Intent intent, int resultCode, String data,
            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
        final LoadedApk.ReceiverDispatcher rd;
        ...
        if (rd != null) {
            rd.performReceive(intent, resultCode, data, extras,
                    ordered, sticky, sendingUser);
        } else ...
    }
    
    • 上面又调用ReceiverDispatcher类型的rd对象的performReceive方法
    public void performReceive(Intent intent, int resultCode, String data,
            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
        //将广播的intent等信息封装为Args对象
        final Args args = new Args(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
        ...
        //调用mActivityThread的post方法并传入了Args对象中的runnable
        //mActivityThread是一个Handler对象,具体指向的就是H
        //将Args对象通过H发送到主线程的消息队列中
        if (intent == null || !mActivityThread.post(args.getRunnable())) {
            if (mRegistered && ordered) {
                IActivityManager mgr = ActivityManager.getService();
                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                        "Finishing sync broadcast to " + mReceiver);
                args.sendFinished(mgr);
            }
        }
    }
    
    • 调用mActivityThread的post方法并传入了Args对象中的runnable,mActivityThread是一个Handler对象,具体指向的就是H,将Args对象中的runnable通过H发送到主线程的消息队列中,Args继承自Runnable,这个消息最终会在Args中的runnable的run方法执行
    public final Runnable getRunnable() {
        return () -> {
            ...
            try {
                ClassLoader cl = mReceiver.getClass().getClassLoader();
                intent.setExtrasClassLoader(cl);
                intent.prepareToEnterProcess();
                setExtrasClassLoader(cl);
                receiver.setPendingResult(this);
                //执行了广播接收者的onReceive方法,这样注册的广播接收者就收到了广播并得到了intent
                receiver.onReceive(mContext, intent);
            } catch...
        };
    }
    
    • getRunnable的run方法中执行了广播接收者的onReceive方法,这样注册的广播接收者就收到了广播并得到了intent

    番外:本地广播

    • 主要是使用LocalBroadcastManager类,对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册,使用demo:
    class LocalBroadcastActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_local_broadcast)
          testLocalBroadcast()
        }
    
        private lateinit var broadcastReceiver: BroadcastReceiver
        private lateinit var lbm: LocalBroadcastManager
        private val localAction = "com.ljy.publicdemo.localAction"
        private fun testLocalBroadcast() {
          broadcastReceiver = object : BroadcastReceiver() {
              /**
               * 接收并出列广播
               */
              override fun onReceive(context: Context?, intent: Intent?) {
                  if (localAction == intent!!.action) {
                      val value = intent.getStringExtra("key_001")
                      LogUtils.d("key_001=$value, do something... ")
                  }
              }
          }
          //创建
          lbm = LocalBroadcastManager.getInstance(this)
          //注册
          lbm.registerReceiver(broadcastReceiver, IntentFilter(localAction))
        }
    
        private fun sendBroadcast() {
          //发送
          val intent = Intent(localAction)
          intent.putExtra("key_001", "value_001")
          lbm.sendBroadcast(intent)
        }
    
        fun onBtnClick(view: View) {
          when (view.id) {
              R.id.button_send_broadcast -> sendBroadcast()
          }
        }
    
        override fun onDestroy() {
          super.onDestroy()
          //解绑
          lbm.unregisterReceiver(broadcastReceiver)
        }
    }
    
    LocalBroadcastManager源码
    //构造方法如下,其本质还是用handler通信
    private LocalBroadcastManager(Context context) {
        mAppContext = context;
        mHandler = new Handler(context.getMainLooper()) {
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MSG_EXEC_PENDING_BROADCASTS:
                        executePendingBroadcasts();
                        break;
                    default:
                        super.handleMessage(msg);
                }
            }
        };
    }
    
    //内部类ReceiverRecord:将receiver和intentFilter封装成ReceiverRecord对象,
    private static final class ReceiverRecord {
            final IntentFilter filter;
            final BroadcastReceiver receiver;
            boolean broadcasting;
            boolean dead;
    
            ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
                filter = _filter;
                receiver = _receiver;
            }
    }
    
    //内部类BroadcastRecord:将ReceiverRecord对象封装在BroadcastRecord对象中
    private static final class BroadcastRecord {
        final Intent intent;
        final ArrayList<ReceiverRecord> receivers;
    
        BroadcastRecord(Intent _intent, ArrayList<ReceiverRecord> _receivers) {
            intent = _intent;
            receivers = _receivers;
        }
    }
    
    //有三个集合
    //一个以receiver为key、以ReceiverRecord列表为value的map
    private final HashMap<BroadcastReceiver, ArrayList<ReceiverRecord>> mReceivers= new HashMap<>();
    //一个以action为key,以ReceiverRecord列表为value的map
    private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap<>();
    //BroadcastRecord对象的集合
    private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList<>();
    
    //注册和解绑的源码就不贴了
    //registerReceiver()就是装填mReceivers,mActions这两个map
    //unregisterReceiver()就是清除mReceivers,mActions
    
    //发送广播源码
    public boolean sendBroadcast(@NonNull Intent intent) {
        synchronized (mReceivers) {
            //。。。省略部分源码,主要就是对intent中的信息进行校验
            //最关键的是下面的装填mPendingBroadcasts,和发送handler消息
                if (receivers != null) {
                    for (int i=0; i<receivers.size(); i++) {
                        receivers.get(i).broadcasting = false;
                    }
                    mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
                    if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
                        mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
                    }
                    return true;
                }
            }
        }
        return false;
    }
    
    //还有一个同步发送广播的方法
     public void sendBroadcastSync(@NonNull Intent intent) {
        if (sendBroadcast(intent)) {
            executePendingBroadcasts();
        }
    }
    
    //上面源码看出一个至关重要的方法executePendingBroadcasts,才是真正调用广播处理的回调
     void executePendingBroadcasts() {
        while (true) {
            final BroadcastRecord[] brs;
            synchronized (mReceivers) {
                final int N = mPendingBroadcasts.size();
                if (N <= 0) {
                    return;
                }
                brs = new BroadcastRecord[N];
                mPendingBroadcasts.toArray(brs);
                mPendingBroadcasts.clear();
            }
            for (int i=0; i<brs.length; i++) {
                final BroadcastRecord br = brs[i];
                final int nbr = br.receivers.size();
                for (int j=0; j<nbr; j++) {
                    final ReceiverRecord rec = br.receivers.get(j);
                    if (!rec.dead) {
                        rec.receiver.onReceive(mAppContext, br.intent);
                    }
                }
            }
        }
    }
    
    • 但是本地广播传输消息时将一切都交给系统负责,无法干预传输中的步骤
    BroadcastReceiver,LocalBroadcastReceiver 区别
    应用场景
    1. BroadcastReceiver用于应用之间的传递消息;
    2. 而LocalBroadcastManager用于应用内部传递消息,比broadcastReceiver更加高效。
    安全
    1. BroadcastReceiver使用的Content API,所以本质上它是跨应用的,所以在使用它时必须要考虑到不要被别的应用滥用;
    2. LocalBroadcastManager不需要考虑安全问题,因为它只在应用内部有效。
    原理方面
    1. 与BroadcastReceiver是以 Binder 通讯方式为底层实现的机制不同,LocalBroadcastManager 的核心实现实际还是 Handler,只是利用到了 IntentFilter 的 match 功能,至于 BroadcastReceiver 换成其他接口也无所谓,顺便利用了现成的类和概念而已。
    2. LocalBroadcastManager因为是 Handler 实现的应用内的通信,自然安全性更好,效率更高。
    Background execution not allowed: receiving Intent 问题解决
    1. 如果是在一个进程中的app组件之间的通信,可以改成使用:LocalBroadcastManager
    2. 如果是在多进程中的app组件之间的通信,可以改成显示广播(explicit broadcasts)
    3. 如果你是在接受系统发的隐式广播,请保证你的sdk在25及以下,直到我们找到更好的解决放法。
    4. 如果你是在编写发送隐式广播,你可以通过直到接收器并且发送定向的显示广播来打破这个限制。方法如下:
    private fun sendImplicitBroadcast(context: Context, intent: Intent) {
        val pm: PackageManager = context.packageManager
        val matches: List<ResolveInfo> = pm.queryBroadcastReceivers(intent, 0)
        for (resolveInfo in matches) {
            val explicit = Intent(intent)
            val cn = ComponentName(
                resolveInfo.activityInfo.applicationInfo.packageName,
                resolveInfo.activityInfo.name
            )
            explicit.component = cn
            context.sendBroadcast(explicit)
        }
    }
    

    参考

    我是今阳,如果想要进阶和了解更多的干货,欢迎关注微信公众号 “今阳说” 接收我的最新文章

    相关文章

      网友评论

        本文标题:Android进阶笔记-4. BroadcastReceiver

        本文链接:https://www.haomeiwen.com/subject/ckcicrtx.html