你真的了解广播吗?

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

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

相关推荐
程序猿进阶16 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
Hacker_Fuchen1 小时前
天融信网络架构安全实践
网络·安全·架构
ProtonBase1 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
工业甲酰苯胺9 小时前
分布式系统架构:服务容错
数据库·架构
拭心10 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
Java程序之猿11 小时前
微服务分布式(一、项目初始化)
分布式·微服务·架构
带电的小王12 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡13 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道13 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频