broadcastreceiver机制-android12(代码片段)

xhBruce xhBruce     2023-03-24     773

关键词:

BroadcastReceiver机制

android12-release
查看android developer 广播概览


1. 广播概览

  一般来说,广播可作为跨应用和普通用户流之外的消息传递系统。应用可以注册接收特定的广播。广播发出后,系统会自动将广播传送给同意接收这种广播的应用。
  广播(Broadcast)分为广播发送和广播接收两个过程,其中广播接收者BroadcastReceiver便是Android四大组件之一。

BroadcastReceiver注册方式分为两类:

  1. 静态广播接注册:通过AndroidManifest.xml的标签来申明的BroadcastReceiver。(受 Android 8.0(API 级别 26)后台执行限制的影响,以 API 级别 26 或更高级别为目标的应用无法再在其清单中注册用于隐式广播的广播接收器。

  2. 动态广播接注册:通过AMS.registerReceiver()方式注册的BroadcastReceiver,动态注册可在不需要时通过unregisterReceiver()取消注册。


广播发送方式可分为三类:

  1. 普通广播:sendBroadcast(Intent) 可并行处理,方法会按随机的顺序向所有接收器发送广播。这称为常规广播。这种方法效率更高,但也意味着接收器无法从其他接收器读取结果,无法传递从广播中收到的数据,也无法中止广播。

  2. 有序广播:sendOrderedBroadcast(Intent, String) 串行处理,一次向一个接收器发送广播。当接收器逐个顺序执行时,接收器可以向下传递结果,也可以完全中止广播,使其不再传递给其他接收器。接收器的运行顺序可以通过匹配的 intent-filter 的 android:priority 属性来控制;具有相同优先级的接收器将按随机顺序运行。

  3. Sticky广播:通过sendStickyBroadcast()发送

2. 注册广播

2.1 时序图

用户调用registerReceiver()方法,而Activity/Service都间接继承于Context抽象类,真正干活是交给ContextImpl类。

2.2 allSticky队列

  • allSticky.add(intent) 匹配成功,则将给intent添加到allSticky队列
  • 当IIntentReceiver为空,则直接返回第一个sticky Intent

2.3 创建BroadcastFilter对象,并添加到接收者队列ReceiverList

  • ReceiverList rl 接收者队列
  • mReceiverResolver.addFilter(bf) 添加ReceiverResolver队列,记录着所有已注册的广播

2.4 所有匹配该filter的sticky广播执行入队操作

  • broadcastQueueForIntent(intent) 获得mFgBroadcastQueuemBgBroadcastQueue
  • queue.enqueueParallelBroadcastLocked(r)将BroadcastRecord加入到并行广播队列mParallelBroadcasts
  • queue.scheduleBroadcastsLocked() 调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播

3. 发送广播

3.1 三方方式发送参数

  • boolean serialized, boolean sticky 传递到broadcastIntentLocked中boolean ordered, boolean sticky
发送serialized/orderdedsticky
sendBroadcastfalsefalse
sendOrderedBroadcasttruefalse
sendStickyBroadcastfalsetrue

3.2 增加sticky广播

  • 增加sticky广播处理 mStickyBroadcastsstickieslist
// Add to the sticky list if requested.
if (sticky) 
    // ... ...
    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
    if (stickies == null) 
        stickies = new ArrayMap<>();
        mStickyBroadcasts.put(userId, stickies);
    
    ArrayList<Intent> list = stickies.get(intent.getAction());
    if (list == null) 
        list = new ArrayList<>();
        stickies.put(intent.getAction(), list);
    
    final int stickiesCount = list.size();
    int i;
    for (i = 0; i < stickiesCount; i++) 
        if (intent.filterEquals(list.get(i))) 
            // This sticky already exists, replace it.
            list.set(i, new Intent(intent));
            break;
        
    
    if (i >= stickiesCount) 
        list.add(new Intent(intent));
    

3.3 查询receivers和registeredReceivers

  • receivers:记录着匹配当前intent的所有静态注册广播接收者;receivers = collectReceiverComponents()通过PKMS根据Intent查询相应的静态receivers。
  • registeredReceivers:记录着匹配当前的所有动态注册的广播接收者;mReceiverResolver.queryIntent() 查询相应的动态注册的广播。
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
         == 0) 
    receivers = collectReceiverComponents(
            intent, resolvedType, callingUid, users, broadcastAllowList);

if (intent.getComponent() == null) 
    if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) 
        // Query one target user at a time, excluding shell-restricted users
        for (int i = 0; i < users.length; i++) 
            if (mUserController.hasUserRestriction(
                    UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) 
                continue;
            
            List<BroadcastFilter> registeredReceiversForUser =
                    mReceiverResolver.queryIntent(intent,
                            resolvedType, false /*defaultOnly*/, users[i]);
            if (registeredReceivers == null) 
                registeredReceivers = registeredReceiversForUser;
             else if (registeredReceiversForUser != null) 
                registeredReceivers.addAll(registeredReceiversForUser);
            
        
     else 
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false /*defaultOnly*/, userId);
    

3.4 处理并序广播

  • broadcastQueueForIntent(intent) 根据intent的flag来判断前台队列或者后台队列
  • queue.enqueueParallelBroadcastLocked(r) 将BroadcastRecord加入到并行广播队列mParallelBroadcasts
  • queue.scheduleBroadcastsLocked() 处理广播
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) 
    // If we are not serializing this broadcast, then send the
    // registered receivers separately so they don't wait for the
    // components to be launched.
    if (isCallerSystem) 
        checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                isProtectedBroadcast, registeredReceivers);
    
    final BroadcastQueue queue = broadcastQueueForIntent(intent);
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
            callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
            requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
            resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
            allowBackgroundActivityStarts, backgroundActivityStartsToken,
            timeoutExempt);
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
    final boolean replaced = replacePending
            && (queue.replaceParallelBroadcastLocked(r) != null);
    // Note: We assume resultTo is null for non-ordered broadcasts.
    if (!replaced) 
        queue.enqueueParallelBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    
    registeredReceivers = null;
    NR = 0;

3.5 将registeredReceivers合并到receivers

3.6 处理串行广播

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, excludedPermissions, appOp, brOptions,
            receivers, resultTo, resultCode, resultData, resultExtras,
            ordered, sticky, false, userId, allowBackgroundActivityStarts,
            backgroundActivityStartsToken, timeoutExempt);

    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);

    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();
    

4. 发送广播小结

Sticky广播:

  1. 广播注册过程处理AMS.registerReceiver,开始处理粘性广播
  2. 创建BroadcastRecord对象
  3. 添加到mParallelBroadcasts队列
  4. 执行queue.scheduleBroadcastsLocked

并行广播:

  1. 广播发送过程处理
  2. 只有动态注册的mRegisteredReceivers才会并行处理
  3. 会创建BroadcastRecord对象
  4. 并添加到mParallelBroadcasts队列
  5. 然后执行queue.scheduleBroadcastsLocked

串行广播:

  1. 广播发送广播处理
  2. 所有静态注册的receivers以及动态注册mRegisteredReceivers合并到一张表处理
  3. 创建BroadcastRecord对象
  4. 并添加到mOrderedBroadcasts队列
  5. 然后执行queue.scheduleBroadcastsLocked

5. scheduleBroadcastsLocked处理

查看下图,不做代码展示说明:

  • scheduleBroadcastsLocked 执行 processNextBroadcast(true)
  • deliverToRegisteredReceiverLocked 通过IApplicationThread最终会调用注册的receiver.onReceive(mContext, intent)方法
  • 先处理并行广播mParallelBroadcasts,在处理串行广播,此时就广播超时监听处理broadcastTimeoutLocked
  • cancelBroadcastTimeoutLocked()取消广播耗时处理;广播ANR查看: ANR Broadcast TimeOut 超时判断
  • 动态注册广播BroadcastFilter处理deliverToRegisteredReceiverLocked
  • 静态广播处理processCurBroadcastLocked
  • 本次广播处理完成都会执行scheduleBroadcastsLocked进行下一条广播处理

broadcastreceiver源码分析(代码片段)

...息,才能接收到消息,Android系统中的广播机制是BroadcastReceiver组件。广播接收者需要首先将自己注册,最终他们是将自己注册到了AMS服务中,当广播发送者发送一个广播的时候࿰ 查看详情

android基础到进阶面试题之broadcastreceiver使用+实例(代码片段)

BroadcastReceiver是什么        BroadcastReceiver是Android四大组件之一,是一种广泛运用在应用程序之间传输信息的机制,通过发送Intent来传送我们的数据。BroadcastReceiver使用场景应用内多个不同组件之间的消息通信。跨应用... 查看详情

android——broadcastreceiver广播机制(自定义广播)(代码片段)

...面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式,可以使用的场景如下:1.同一app内部的同一组件内的消息通信(单... 查看详情

android——broadcastreceiver广播机制(自定义广播)(代码片段)

...面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式,可以使用的场景如下:1.同一app内部的同一组件内的消息通信(单... 查看详情

broadcastreceiver源码分析(代码片段)

...息,才能接收到消息,Android系统中的广播机制是BroadcastReceiver组件。广播接收者需要首先将自己注册,最终他们是将自己注册到了AMS服务中,当广播发送者发送一个广播的时候,首先发送到AMS服务中,然后... 查看详情

androidbroadcastreceiver详解(代码片段)

...分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式,可以使用的场景如下:1)同一app内部的同一组件内的消息通信(单个或多个线程之间... 查看详情

broadcastreceiver详解(基础篇)

...播)是一种广泛运用的应用程序之间传输信息的机制,而BroadcastReceiver(广播接收器)则是用于接收来自系统和应用的广播对并对其进行响应的组件,Android中我们要发送的广播内容是一个Intent,这个Intent中可以携带我们要传送的... 查看详情

[android5.1]broadcast机制

...通知机制。有广播,当然也得有广播接收器,即BroadcastReceiver。BroadcastReceiver是一种全局的监听器,用于监听系统全局的广播消息。它可以接收来自系统和应用的广播。应用程序可以使用它对外部事件进行过滤,只... 查看详情

android广播:broadcast与broadcastreceiver

一、广播简介1.广播传播机制:  广播接收器,也被称为全局事件,或系统事件。  当Android系统中任何程序有动作时,如果想通知其他程序,采用广播的方式进行传播是非常有效的。广播从理论上说,... 查看详情

22androidbroadcast广播机制

...广播分为广播发送和广播接收两个过程,其中广播接收者BroadcastReceiver便是Android四大组件之一。BroadcastReceiver分为两类:从广播发送方式可分为三类:广播在系统中以BroadcastRecord对象来记录,该对象有几个时间相关的成员变量.广... 查看详情

broadcastreceiver源码解析

1,简介BroadcastReceiver,中文直译为“广播接收者”,在Android系统中,广播主要用在组件与组件之间进行消息传递。组件与组件之间可以是同一个进程,也可以是不同进程。既然是可以跨进程的,那么可以... 查看详情

为啥android要使用各种broadcastreceiver

作为Android四大组件之一的BroadcastReceiver(广播接收者),同Activity(活动)一样,经常被大家用到,网上也是一堆对它的讲解,那么为什么Android要用广播接收者这种机制呢?广播分为:普通广播和有序广播1.Normalbroadcasts(普通广... 查看详情

android广播机制(代码片段)

...面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式, 查看详情

broadcastreceiver

packagecom.android.broadcastreceiver;importandroid.app.Notification;importandroid.app.NotificationManager;importandroid.app.PendingIntent;importandroid.content.BroadcastReceiver;importandroid.content. 查看详情

为啥 BroadcastReceiver 需要一个默认构造函数?

】为啥BroadcastReceiver需要一个默认构造函数?【英文标题】:WhydoesBroadcastReceiverneedadefaultconstructor?为什么BroadcastReceiver需要一个默认构造函数?【发布时间】:2012-12-2507:25:14【问题描述】:我创建了一个由Service构建的BroadcastReceive... 查看详情

BroadcastReceiver 是不是只监听变化?

】BroadcastReceiver是不是只监听变化?【英文标题】:DoesaBroadcastReceiveronlylistentochanges?BroadcastReceiver是否只监听变化?【发布时间】:2012-07-2215:05:17【问题描述】:我正在阅读指南here,关于设置BroadcastReceiver以检查电池的变化。它... 查看详情

broadcastreceiver

广播接收者案例_ip拨号器 (1)定义一个类继承BroadCastReceiver   publicclassOutGoingCallReceiverextendsBroadcastReceiver{//当接收到外拨电话的事件的时候回执行这个方法@OverridepublicvoidonReceive(Contextcontext,Intentintent) 查看详情

采用单独扩展 BroadcastReceiver 的类

】采用单独扩展BroadcastReceiver的类【英文标题】:TakingaclassthatextendsBroadcastReceiveralone【发布时间】:2013-09-3001:25:58【问题描述】:有许多扩展BroadcastReceiver的类示例,可以通过意图从另一个类激活。类也从BroadcastReceiver扩展而来,... 查看详情