你真的了解广播吗?

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

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

相关推荐
秋千码途14 分钟前
小架构step系列06:编译配置
架构
打好高远球2 小时前
如何用AI破解相亲信息不对称
架构
泊浮目2 小时前
未来数据库硬件-网络篇
数据库·架构·云计算
vocal2 小时前
【我的安卓第一课】Android 多线程与异步通信机制(1)
android
鹏程十八少2 小时前
8.Android 设计模式 适配器模式 在商业项目中的落地
架构
不骞2 小时前
5.solidity的数据结构
架构
星辰大海的精灵2 小时前
使用Docker和Kubernetes部署机器学习模型
人工智能·后端·架构
顾林海2 小时前
ViewModel 销毁时机详解
android·面试·android jetpack
某非著名程序员3 小时前
Flutter 新手绕不过的坑:ListView 为啥顶部老有空白?
flutter·客户端
魔镜魔镜_谁是世界上最漂亮的小仙女3 小时前
java-web开发
java·后端·架构