你真的了解广播吗?

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

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

相关推荐
ZOMI酱3 分钟前
【AI系统】GPU 架构与 CUDA 关系
人工智能·架构
小白也想学C4 分钟前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程11 分钟前
初级数据结构——树
android·java·数据结构
闲暇部落2 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX4 小时前
Android 分区相关介绍
android
大白要努力!5 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee5 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood6 小时前
Perfetto学习大全
android·性能优化·perfetto