你真的了解广播吗?

今天我们聊一个大家耳熟能详,经常用到的东西 ------------ 广播。先来看看官方给出的解释:

Generally speaking, broadcasts can be used as a messaging system across apps and outside of the normal user flow.

广播的作用如其名,可以跨进程、跨应用的传递消息。

我们都知道广播的注册在Android中分两类:静态注册动态注册。那么我们先来研究下广播的注册具体做了什么

静态注册

指的是直接在AndroidManifest.xml使用receiver标签配置信息。这里以订阅服务配置接收推送消息的广播为例:

ini 复制代码
<receiver
    android:name="com.lotus.subscription.PushMessageReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="ecarx.intent.action.PUSH_RECEIVER" />
    </intent-filter>
</receiver>

1. Receiver标签的识别流程

既然是直接在AndroidManifest.xml使用receiver标签,那么想要找到这个标签的对应信息,肯定需要涉及文件的解析。

1.1 APK文件的安装

APK文件的安装流程也较为复杂,这里就不从头开始分析了,直接从PackageManagerService中处理安装动作开始进行分析:

  1. 执行PackageManagerService#installStage时,发送一条MessageHandler

2. 在Handler中处理Message#obj方法传递过来的InstallParams#startCopyInstallParams#startCopy方法中调用InstallParams#handlerstartCopyInstallParams#handlerReturnCode

  1. InstallParams#handlerReturnCode中调用了InstallParams#processPendingInstall
  1. InstallParams#processPendingInstall中根据不同的情况调用InstallParams#tryProcessInstallRequestInstallParams#processInstallRequestsAsync,在最终也会调用到InstallParams#processInstallRequestsAsync
  1. 会在Handler中将收到的InstallRequest依次执行doPreInstall(校验返回值状态)installPackagesTracedLI(执行installPackagesLI安装包解析APK)doPostInstall(同安装前一样校验状态)restoreAndPostInstall(备份信息或失败处理以及安装成功的逻辑)

1.2 APK文件解析

我们需要关注的是如何解析AndroidManifest.xml文件中的receiver标签,那么只需要关注installPackagesLI方法即可。

  1. 调用preparePackageLI去准备解析包信息
  1. 接着调用parsePackage读取文件信息
  1. 在PackageParser2#parsePackage中调用ParsingPackageUtils#parsePackage解析包内容
  1. 此时解析文件,分为包含文件目录的解析parseClusterPackage单个整体包解析parseMonolithicPackage,最终都会调用parseBaseApk
  1. 后面会调用到parseBaseApkTags来解析AndroidManifest.xml中的相关标签
  1. 通过前置的校验后,调用parseBaseApplication来解析application标签下的内容。

2. 将<receiver>标签下的信息解析后进行记录

通过Xml解析,按照对应的标签,找到<receiver>标签并解析其内容

最后将解析的结果ParseResult,通过ParsingPackage#addReceiver存储在ParsingPackageImpl#receivers

动态注册

在静态注册的方式中,我们结合源码对具体流程进行了展示。所以在动态注册中,通过流程图来对调用方式进行阐述。

graph TD Context#registerReceiver --> ContextImpl#registerReceiver --> ContextImpl#registerReceiverInternal --> |receiver转化为IIntentReceiver|C{IIntentReveiver} C-->D(LoadedApk.ReceiverDispatcher) E(LoadedApk.ReceiverDispatcher#getIIntentReciver) --> D F(ActivityManagerService#registerReceiver) <--> |AIDL| E

指定onReceiver收到的线程

通常我们使用广播时,在onReceiver接收消息时,都默认会在主线程。那么是否存在onReceiver在其他线程调用的情况?

在动态注册时,可以通过传递需要接收消息的线程对应的Handler来实现此效果:

less 复制代码
 /**
* Register to receive intent broadcasts, to run in the context of
* <var>scheduler</var>.  See
* {  @link  #registerReceiver(BroadcastReceiver, IntentFilter)} for more
* information.  This allows you to enforce permissions on who can
* broadcast intents to your receiver, or have the receiver run in
* a different thread than the main application thread.
*
* <p>See {  @link  BroadcastReceiver} for more information on Intent broadcasts.
*
* <p>As of {  @link  android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers
* registered with this method will correctly respect the
* {  @link  Intent#setPackage(String)} specified for an Intent being broadcast.
* Prior to that, it would be ignored and delivered to all matching registered
* receivers.  Be careful if using this for security.</p>
*
*  @param  receiver The BroadcastReceiver to handle the broadcast.
*  @param  filter Selects the Intent broadcasts to be received.
*  @param  broadcastPermission String naming a permissions that a
*      broadcaster must hold in order to send an Intent to you.  If null,
*      no permission is required.
*  @param  scheduler Handler identifying the thread that will receive
*      the Intent.  If null, the main thread of the process will be used.
*
*  @return  The first sticky intent found that matches <var>filter</var>,
*         or null if there are none.
*
*  @see  #registerReceiver(BroadcastReceiver, IntentFilter)
*  @see  #sendBroadcast
*  @see  #unregisterReceiver
*/
@Nullable
public abstract Intent registerReceiver(BroadcastReceiver receiver,
        IntentFilter filter, @Nullable String broadcastPermission,
        @Nullable Handler scheduler);

这样其注册时,就会将传递的Handler信息进行记录,在收到消息时就会通过此Handler切换到对应线程后执行onReceiver

相关推荐
百锦再1 小时前
React编程高级主题:测试代码
android·前端·javascript·react.js·前端框架·reactjs
2501_916008892 小时前
全面介绍Fiddler、Wireshark、HttpWatch、SmartSniff和firebug抓包工具功能与使用
android·ios·小程序·https·uni-app·iphone·webview
啊森要自信3 小时前
CANN ops-cv:面向计算机视觉的 AI 硬件端高效算子库核心架构与开发逻辑
人工智能·计算机视觉·架构·cann
玉梅小洋3 小时前
Windows 10 Android 构建配置指南
android·windows
2的n次方_4 小时前
CANN ascend-transformer-boost 架构解析:融合注意力算子管线、长序列分块策略与图引擎协同机制
深度学习·架构·transformer
Libraeking5 小时前
视觉篇:Canvas 自定义绘图与高级动画的华丽圆舞曲
android·经验分享·android jetpack
Fushize5 小时前
多模块架构下的依赖治理:如何避免 Gradle 依赖地狱
android·架构·kotlin
大雨淅淅5 小时前
Eureka从入门到精通:开启微服务架构的钥匙
微服务·云原生·eureka·架构
Jomurphys6 小时前
Kotlin - 类型别名 typealias
android·kotlin
Haha_bj6 小时前
Flutter ——flutter_screenutil 屏幕适配
android·ios