你真的了解广播吗?

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

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

相关推荐
工程师老罗6 小时前
如何在Android工程中配置NDK版本
android
yunteng5218 小时前
通用架构(同城双活)(单点接入)
架构·同城双活·单点接入
麦聪聊数据9 小时前
Web 原生架构如何重塑企业级数据库协作流?
数据库·sql·低代码·架构
Libraeking9 小时前
破壁行动:在旧项目中丝滑嵌入 Compose(混合开发实战)
android·经验分享·android jetpack
程序员侠客行9 小时前
Mybatis连接池实现及池化模式
java·后端·架构·mybatis
市场部需要一个软件开发岗位10 小时前
JAVA开发常见安全问题:Cookie 中明文存储用户名、密码
android·java·安全
bobuddy11 小时前
射频收发机架构简介
架构·射频工程
桌面运维家11 小时前
vDisk考试环境IO性能怎么优化?VOI架构实战指南
架构
JMchen12311 小时前
Android后台服务与网络保活:WorkManager的实战应用
android·java·网络·kotlin·php·android-studio
crmscs12 小时前
剪映永久解锁版/电脑版永久会员VIP/安卓SVIP手机永久版下载
android·智能手机·电脑