Android---底层剖析 Window、Activity、View 三者关系

news2024/11/20 0:42:14

对于一个 Android 工程师来讲,或多或少都听说过 Window 的概念,并且隐约感受到它在 Activity 和 View 之间应该发挥着某种连接的作用。但如果要说出这三者之间的关系,多数 android 工程师都不知道从何下手。

Activity 的 setContentView

Activity 是 Android 开发人员使用最频繁的 API 之一。最初在接触 Android 开发时,很多人都会认为它是负责将 layout 布局中的控件渲染绘制出来的。原因很简单,因为我们认为

\bullet 想显示一个新的界面时,都是通过 start 一个新的 Activity 方式;

\bullet 想显示的内容或者布局,只需要在 Activity 中添加一行 setContentView

剩下的 Activity 都自动的帮我们搞定。但是从来没有去创建一个 window 来绑定 UI 或者 View 元素。

点开 setContentView 的源码,如下

可以看出,Activity 几乎什么都没有做,将操作直接交给了一个 window 来处理。getWindow 返回的是 Activity 中的全局遍历 mWindow,它是 Window 窗口类型。那么这个 mWindow 是什么时候赋值的呢?

在 startActivity 的过程中,最终代码会调用到 ActivityThread 中的 performLaunchActivity 方法通过反射创建 Activity 对象,并执行其 attach 方法。Window 就是在这个方法中被创建

在 attach 方法中,将 mWindow 初始化为一个 PhoneWindow 类型。实际上,整个 Android 系统中,Window 只有一个实现类 PhoneWindow

接下来调用 setWindowManager 方法,将系统 WindowManager 传给 PhoneWindow

最终,在 PhoneWindow 中持有了一个 WindowManagerImpl 的引用。

PhoneWindow 的 setContentView

Activity 将 setContentView 的操作交给了 PhoneWindow,看一下其实现过程

图中1处调用,如果 mContentParent 为 null,则调用 installDecor() 初始化 DecorView 和 mContentParent;图中2处将我们调用的 setContentView 传入的布局添加到 mContentParent 中

 可以看出,在 PhoneWindow 中,默认有一个 DecorView,实际上是一个 FrameLayout。在 decorView 中,默认自带一个 mContentParent,实际上是一个 ViewGroup。我们自己实现的布局是被添加到 mContentParent 中的。因此,经过 setContentView 之后,PhoneWindow 内部的 View 关系,如下图所示:

目前为止,PhoneWindow 中只是创建了一个 DecorView,并在 DecorView 中添加了我们在 Activity 中传入的 layout 布局。但此时,DecorView 还没有与 Activity 建立任何联系,也没有被绘制到界面显示,那么 DecorView 是何时被绘制到屏幕上的呢?

刚接触 Android 学习生命周期时,经常会看到相关文档 Activity 执行到 onCreate() 时 Activity 的内容还并不可见,只有执行完 onResume() 之后,Activity 中的内容才是屏幕可见状态。造成这种现象的原因是:

onCreate 阶段只是初始化了 Activity 需要显示的内容;onResume 阶段会将 PhoneWindow 中的 DecorView 真正的绘制到屏幕上

在 Activity 的 handleResumeActivity 中,会调用 WindowManager 的 addView 方法,将 DecorView 添加到 WMS 上,如下代码所示:

WindowManager 的 addView 结果:

\bullet DecorView 被渲染绘制到屏幕上显示;

\bullet DecorView 可以接收屏幕触摸事件。

WindowManager 的 addView

PhoneWindow 只是负责处理一些应用窗口通用的逻辑,设置标题栏、导航栏等。但真正完成把一个 View 作为窗口添加到 WMS 的过程是由 WindowManager 来完成的。WindowManger 是接口类型,它的真正实现是 WindowManagerImpl 类。它的 addView 方法如下

WindowManagerImpl 也是一个空壳,它调用了 WindowManagerGlobal 的 addView 方法。

WindowManagerGlobal 是一个单例,每一个进程中只有一个实例对象,如上图红框中所示。在其 addView 方法中,创建了一个最关键ViewRootImpl 对象,然后通过 ViewRootImpl 的 setView 方法,将 View 添加到 WMS 中

ViewRootImpl 的 setView

图中1处的 requestLayout 是刷新布局的操作,调用此方法后 ViewGroup 所关联的 View 也执行 measure、layout、draw 等操作。确保 view 被添加到 Window 上显示到屏幕之前,已经测量和绘制操作。图中2处调用 mWindowSession 的 addToDisplay 方法,将 View 添加到 WMS 中。mWindowSession 是 WindowManagerGlobal 中的单例对象,初始化代码如下

sWindowSession 实际上是 IWindowSession 类型,是一个 Binder 类型。真正的实现类是 System 中的 Session 。图中中,红框中的内容就是用 AIDL 获取 System 进程中的 Session 对象。即 addToDisplay 代码如下

图中的 mService 就是 WMS。至此,Window 已经成功的被传递给了 WMS,剩下的工作就全部转移到系统中的进程 WMS 来完成最终的添加操作。

上面我们提到 addView 成功的另一个标志就是能够接收触屏事件。通过对 setContentView 的流程分析,可以看出:添加 View 的操作实质上是 PhoneWindow 在全盘操作,背后负责人是 WMS。反之,Activity 至始至终没有什么参与感。但是,当触屏事件发生之后 Touch 事件首先被传入到 Activity,然后被下发到布局中的 ViewGroup 或者 View。那么 touch 事件是如何传递到 Activity 上的呢?

ViewRootImpl 中的 setView 方法,除了调用 IWindowSession 执行跨进程添加 View 之外。还有一项重要的操作,就是设置输入事件的处理

上图红框中,设置了一系列的输入通道。一个触屏事件的发生是由屏幕发起,然后经过驱动层一系列的优化计算,通过 socket 跨进程通知 Android 的 Framework 层,实际上就是 WMS。最终,屏幕的触摸事件被发送到上面的输入管道中。

这些输入管道实际上是一个链表结构。当某一个屏幕触摸事件到达其中的 ViewPostImeInputStage时,会经过 onProcess 来处理,如下所示

可以看到,在 onProcess() 方法中,最终调用了一个 mView 的 dispatchPointerEvent() 方法,mView 就是 PhoneWindow 中的 DecorView。而 dispatchPointerEvent 是被 View.java 实现的

最终,调用了 PhoneWindow 中的 callback.dispatchTouchEvent() 方法。那这个 callback 是不是 Activity 呢?

在启动 Activity 阶段,创建 Activity 对象并调用 attach 方法时,有如下一段代码

果然,将 Activity 自身传递给了 PhoneWindow。

Activity 的 dispatchTouchEvent 方法

touch 事件只是在 Activity 中绕了一圈,最终还是回到了 PhoneWindow 中的 DecorView 来处理。剩下的就是从 DecorView 开始,将事件层层传递给子 View 中了。

总结
通过setContentView的流程,分析了Activity、Window和 View 之间的关系。整个过程Activity表面上参与度比较低,大部分View的添加操作都被封装到Window中实现。Activity能够更简单的实现Window和View的操作逻辑。

整个流程需要注意:

1. 一个 Activity 中有一个 Window,也就是 PhoneWindow 对象。在 PhoneWindow 中有一个 DecorView,在 setContentView 中会将 layout 填充到此 DecorView 中。

2. 一个应用程序中只有一个 WindowManagerGlobal对象,因为在 ViewRootImpl 中它是 static 静态类型。

3. 每一个 PhoneWindow 对应一个 ViewRootImplement 对象。

4. WindowManagerGlobal 通过调用 ViewRootImpl 的 setView 方法,完成 window 的添加过程。

5. ViewRootImpl 的 setView 方法中主要完成两件事情:View渲染(requestLayout)以及接收触摸事件。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1149830.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前段基础入门之】=>CSS3新特性 transition 过渡

导语 过渡可以在不使用 Flash 动画,不使用 JavaScript 的情况下,让元素从一种样式,平滑过渡为另一种样式 【属性】: transition-property 作用:定义哪个属性需要过渡,只有在该属性中所定义的可变换属性&…

Maven进阶系列-继承和聚合

Maven进阶系列-继承和聚合 文章目录 Maven进阶系列-继承和聚合1. 继承2. 继承的作用2.1 在父工程中配置依赖的统一管理2.2 在父工程中声明自定义属性2.3 父工程中必须要继承的配置 3. 聚合4. 聚合的作用 1. 继承 Maven工程之间存在继承关系,例如工程B继承工程A&…

【数据挖掘 | 数据预处理】缺失值处理 重复值处理 文本处理 确定不来看看?

🤵‍♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…

CESM模型教程

详情点击公众号链接:CESM模型教程 第一:运行前的准备 CESM 运行的系统和软件环境 CESM需要什么运行环境 CESM2.0运行环境的搭建 第二:Linux系统及编译 CESM 运行需要的Linux及编译 Linux的基础 Linux编译的基础 基于Make 和CMake的编译…

ubuntu(18.04) 安装 blast

1、下载 https://ftp.ncbi.nlm.nih.gov/blast/executables/blast/LATEST/2、解压,配置环境变量 tar zvxf ncbi-blast-2.14.1-x64-linux.tar.gz解压后改名为 blast 配置环境变量,可以不配置 使用的时候直接绝对路径使用 vim ~/.bashrc 将下面添加道最…

Goland连接服务器/虚拟机远程编译开发

创建SSH连接 SSH用于与远程服务器建立连接 Settings -> Tools -> SSH Configurations 添加新的ssh连接,Host为ip地址,Username为用户名,认证方式这里选择密码验证 全部填完后可以点击Test Connection测试连接是否成功 创建Deployment…

【Overload游戏引擎细节分析】PBR材质Shader---完结篇

PBR基于物理的渲染可以实现更加真实的效果,其Shader值得分析一下。但PBR需要较多的基础知识,不适合不会OpenGL的朋友。 一、PBR理论 PBR指基于物理的渲染,其理论较多,需要的基础知识也较多,我在这就不再写一遍了&…

带有强大提醒功能的电脑便签工具

在这个充满节奏感的现代生活中,每一天都需要精确规划和提醒,以确保工作计划得以按时完成。为了做到这一点,你需要一款强大的电脑便签工具,它不仅能让你记录工作计划,还能在关键时刻提醒你。 在电脑上记录工作计划是一…

【Amazon】跨AWS账号资源授权存取访问

文章目录 一、实验框架图二、实验过程说明三、实验演示过程1、在A账号中创建S3存储桶2、在A账号创建S3存储桶访问策略3、在A账号创建信任开发账号的角色4、在B账号为用户添加内联策略5、在B账号中切换角色,以访问A账号中的S3资源 四、实验总结 一、实验框架图 本次…

pgAdmin 4 v7.8 发布,PostgreSQL 开源图形化管理工具

导读pgAdmin 是 PostgreSQL 领先的开源图形化管理工具。pgAdmin 4 旨在满足新手和有经验的 Postgres 用户的需求,提供强大的图形界面,简化了数据库对象的创建、维护和使用。 pgAdmin 开发团队日前发布了 pgAdmin 4 v7.8 版本,这个版本包括 21…

外汇天眼:以下平台牌照被撤销,速度远离!

监管信息早知道!外汇天眼将每周定期公布监管牌照状态发生变化的交易商,以供投资者参考,规避投资风险。如果平台天眼评分过高,建议投资者谨慎选择,因为在外汇天眼评分高不代表平台没问题! 以下是监管牌照发生…

【地理位置识别】IP归属地应用的特点

IP归属地应用是一类用于确定特定IP地址的地理位置信息(通常是城市、地区或国家)的工具和服务。以下是IP归属地应用的几个主要特点: 地理位置识别: IP归属地应用主要用于确定IP地址的地理位置。这可以帮助组织更好地了解其网站访问…

CAD需要学c语言嘛?

CAD需要学c语言嘛? AutoCAD 和 C 语言没有关系的。 如果非要说是 AutoCAD 和哪个编程语言有关系,那应该是 VBA, 可以通过 VBA 编程,最近很多小伙伴找我,说想要一些c语言资料,然后我根据自己从业十年经验,熬…

免费提取视频号视频工具有哪些,这个4种方法亲测可用!

很多朋友对视频号都是比较依赖的,另外关于视频号视频下载,一直想找一个关于免费提取视频的方法,今天我就来聊聊该如何使用。 方法一:录屏 在选择需要的设备,并在应用商店搜索录屏工具,或者直接采用手机自…

亚马逊,速卖通,美客多如何打造爆款商品,排名提升榜首

1、产品Listing的完整性 Listing是亚马逊A9算法认识你产品的基础,在发布一条listing的时候,尽可能地做到最好!在准备一条listing之前,一定事先要收集、整理足够多的产品关键词,在优化listing内容的时候填充进去。仔细观察优秀竞品…

《进化优化》第12章 差分进化算法

文章目录 算法流程12.1 基本差分进化算法12.2 差分进化的变种12.2.1 试验向量12.2.2 变异向量12.2.3 比例因子的调整 12.3 离散优化12.3.1 混合整数差分进化12.3.2 离散差分进化 12.4 差分进化与遗传算法 算法流程 12.1 基本差分进化算法 差分进化是为了优化n维连续域中的函数…

人工智能云服务(Alaas)

目录 1、概念介绍 2、人工智能云服务解决了什么问题? 2.1 节约部署成本 2.2 海量数据和机器学习 2.3 降低用户使用人工智能服务的成本 3、人工智能云服务的类型 3.1 公有云 3.2 私有云 3.3 混合云 4、人工智能云服务案例 4.1 微信小程序 “识花君” 4.2…

文件改名,轻松添加前缀顺序编号,文件改名更高效!

您是否曾经需要批量修改文件名,并希望在文件名中添加特定的前缀或顺序编号?现在,我们为您带来了一款全新的文件改名工具,帮助您轻松解决这个问题! 第一步,进入文件批量改名高手主页面,在板块栏…

为什么我觉得Rust比C++复杂得多?

为什么我觉得Rust比C复杂得多? Rust自学确实有一定门槛,很多具体问题解决起来搜索引擎也不太帮的上忙,会出现卡住的情况,卡的时间长了就放弃了。最近很多小伙伴找我,说想要一些c语言资料,然后我根据自己从…

MySQL扩展语句和约束条件

MySQL扩展语句 create TABLE if not exists ky32 (id int(4) zerofill primary key auto_inc rement, #表示该字段可以自增长,默认从1开始每条记录会自动递增1name varchar(10) not null,cradid int(10) not null unique key,hobby varchar (50))&#x…