【15】Android基础知识之Window(一)

概述

这篇文章纠结了很久,在想需要怎么写?因为window有关的篇幅,如果需要讲起来那可太多了。从层级,或是从关联,总之不是很好开口。这次也下定决心,决定从浅入深的讲讲window这个东西。

Window

Window是什么,直译是窗口,我们了解过Android应用显示层级就知道,一个应用从下到上分别是:Activity-Window-DecorView-ViewGroup-View,大致是这样的一个层级包裹。可说了这么多,还是没有说清楚window是什么?有一句话是这样说的:Window是视图的容器,视图是Window的内容。
在这里插入图片描述
又打个比方,把视图View比作水,Window比作装水的瓶子,如果没有瓶子,水就不知道放在哪里,根据瓶子的形状,大小,倒入的水就会在瓶子限制的形状,大小内呈现什么样子。这样一讲,是不是就更清楚了点呢。

Window创建

先说一下Activity,在attach方法中,会创建一个window,它是抽象的,创建的是它的实现类PhoneWindow。为什么从Activity说起呢,因为Activity是我们最常见的组件。除了Activity,Dialog和Toast也有他们的window,实现类通常也是PhoneWindow。它们的window创建,可以自行分析一下。

// Activity.java   @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)final void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,IBinder shareableActivityToken) {attachBaseContext(context);mFragments.attachHost(null /*parent*/);mActivityInfo = info;// 创建windowmWindow = new PhoneWindow(this, window, activityConfigCallback);mWindow.setWindowControllerCallback(mWindowControllerCallback);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {mWindow.setSoftInputMode(info.softInputMode);}if (info.uiOptions != 0) {mWindow.setUiOptions(info.uiOptions);}mUiThread = Thread.currentThread();mMainThread = aThread;mInstrumentation = instr;mToken = token;mAssistToken = assistToken;mShareableActivityToken = shareableActivityToken;mIdent = ident;mApplication = application;mIntent = intent;mReferrer = referrer;mComponent = intent.getComponent();mTitle = title;mParent = parent;mEmbeddedID = id;mLastNonConfigurationInstances = lastNonConfigurationInstances;if (voiceInteractor != null) {if (lastNonConfigurationInstances != null) {mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;} else {mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,Looper.myLooper());}}//设置window的管理者mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);}
Window管理

WindowManager,Window的管理者,上层窗口的管理,都是依赖它,而下层,我们在之后的文章会陆续揭开。从上述贴的aosp中Activity#attach源码可以看到,不仅仅创建window,获取WindowManager,并把它设置到我们创建的window中,也是在attach中进行的。而其中WindowManager是通过系统服务的方式获取的,这种获取的方式,可以认为是一种单例,ContextImpl在执行getSystemService会判断是否已经创建过了WindowManager,否则就创建一个返回。

不过要注意的是,这里的WindowManager也是抽象的概念,它是一个接口,有具体的实现WindowManagerImpl。而比较有趣的事情是,WindowManagerImpl内部有一个单例对象WindowManagerGlobal,关于View的操作都转发给了它去完成的。WindowManagerImpl通过这种代理的方式,让使用更加的灵活,使用者不需要关心具体的窗口管理实现细节,而可以在不同的上下文对象中使用。
在这里插入图片描述
这样一来,看上面这张图就很清晰的了解他们之间的关系了。唯一遗漏的可能就是ViewManager,我们知道WindowManager是一个接口,但是它也同样继承了一个ViewManager的接口类,这个类顾名思义是可以看出来的,对View进行管理。其内部很简单,就是View的添加、更新、删除的接口方法。

// ViewManager.java
public interface ViewManager
{/*** Assign the passed LayoutParams to the passed View and add the view to the window.* <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming* errors, such as adding a second view to a window without removing the first view.* <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a* secondary {@link Display} and the specified display can't be found* (see {@link android.app.Presentation}).* @param view The view to be added to this window.* @param params The LayoutParams to assign to view.*/public void addView(View view, ViewGroup.LayoutParams params);public void updateViewLayout(View view, ViewGroup.LayoutParams params);public void removeView(View view);
}

不知道有没有注意到,上面我们提到过,WindowManagerGlobal作为WindowManager真正的实现类,它帮助WindowManagerImpl操作的,就是对View的操作,可见ViewManager的接口的具体实现,在WindowManagerGlobal中能找到真正的实现逻辑。

Window和View的关联

回到第一张界面层级图,我们讲了Activity创建了window,讲了window的具体实现,讲了window管理其中的view是通过WindowManager,但是没有讲到DecorView。它在window和view关联中起了重要的作用。

我们知道的DecorView是什么,装饰视图?content view可以理解为内容视图,就是开发的应用界面,title view却不是界面中的标题。而更多理解为是除去应用部分,通用的一些样板界面,比如状态栏,菜单栏等,一些应用都会共有的部分。

解释了DecorView,那它是怎么创建的,可以去PhoneWindow里找找看。我们Activity在设置视图的时候,通常都是通过setContentView来实现的,其中两个重要的点,通过分析源码来介绍一下。

    @Overridepublic void setContentView(View view, ViewGroup.LayoutParams params) {// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window// decor, when theme attributes and the like are crystalized. Do not check the feature// before this happens.if (mContentParent == null) {//安装 装饰视图installDecor();} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {view.setLayoutParams(params);final Scene newScene = new Scene(mContentParent, view);transitionTo(newScene);} else {//添加传入的viewmContentParent.addView(view, params);}mContentParent.requestApplyInsets();final Callback cb = getCallback();if (cb != null && !isDestroyed()) {cb.onContentChanged();}mContentParentExplicitlySet = true;}

installDecor(),创建装饰视图,并且将mDecor设置给当前这个window;判断mContentParent是否为空,为空则创建一个mContentParent并返回。
这里简单的贴一下创建的代码ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

// PhoneWindow.java
private void installDecor() {mForceDecorInstall = false;if (mDecor == null) {mDecor = generateDecor(-1);mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);mDecor.setIsRootNamespace(true);if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);}} else {mDecor.setWindow(this);}if (mContentParent == null) {mContentParent = generateLayout(mDecor);

mContentParent#addView,上面看到了ContentParent是一个ViewGroup,在创建的过程中需要传入mDecor,可见ContentParent的约束是依赖mDecor的,即ContentParent是DecorView中的一个ViewGroup。最后通过addView的方法,把内容View添加进去。

梳理一下他们的关联:
window - DecorView - ContentParent - View

总结

1、window是view的容器,view是window的具体内容。
2、window的实现是PhoneWindow。
3、window的管理类是WindowManagerImpl。
4、window把View相关的操作交给了WindowManagerGlobal。
5、window和View的关联是通过DecorView

这样一来,应用层的window,以及相关的管理者,就基本将明白了。但是离我们需要弄明白的事情还有很多,之后会开始分析一个很重要的角色ViewRootImpl

AOSP14源码

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

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

相关文章

Win10+Docker配置TensorRT环境

1.Docker下载和安装 Docker下载:Install Docker Desktop on Windows Docker安装: 勾选直接下一步就行,安装完成后需要电脑重启。 重启后,选择Accept—>Continue without signing in—>skip survey. 可以进入下面页面,并且左下角是绿色的,显示e…

【踩坑日记】【教程】嵌入式 Linux 通过 nfs 下载出现 T T T T [Retry count exceeded: starting again]

文章目录 1 本篇文章解决的问题2 问题解决原理3 问题环境4 开启 ubuntu-20.04 的 nfs24.1 确认 nfs2 是否已经开启4.2 开启 nfs2 5 卸载 iptables5.1 卸载 iptables5.2 禁用 ufw5.3 尝试重新下载 6 原理分析6.1 nfs2 开启部分6.2 卸载 iptables 部分 7 后记7.1 拓扑结构一7.2 拓…

打包一个自己的Vivado IP核

写在前面 模块复用是逻辑设计人员必须掌握的一个基本功&#xff0c;通过将成熟模块打包成IP核&#xff0c;可实现重复利用&#xff0c;避免重复造轮子&#xff0c;大幅提高我们的开发效率。 接下来将之前设计的串口接收模块和串口发送模块打包成IP核&#xff0c;再分别调用…

Automation Anywhere推出新一代AI+自动化企业系统,助力企业实现10倍商业增长

RPA厂商纷纷进军AI Agent ( AI 代理)领域&#xff0c;陆续推出创新产品。最近&#xff0c;Automation Anywhere宣布推出其新的AI 自动化企业系统&#xff0c;该系统结合AI和自动化技术&#xff0c;以实现指数级的业务成果。 在Imagine 2024大会上首次亮相的这款新产品&#xf…

redis基本类型和订阅

redis-cli -h <host> -p <port> -a <password> 其中&#xff0c;< host>是Redis服务器的主机名或IP地址&#xff0c;< port>是Redis服务器的端口号&#xff0c;< password>是Redis服务器的密码&#xff08;如果有的话&#xff09;。 set …

Python | Leetcode Python题解之第240题搜索二维矩阵II

题目&#xff1a; 题解&#xff1a; class Solution:def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:m, n len(matrix), len(matrix[0])x, y 0, n - 1while x < m and y > 0:if matrix[x][y] target:return Trueif matrix[x][y] > tar…

【java】力扣 合并两个有序数组

文章目录 题目链接题目描述代码第一种第二种 题目链接 88.合并两个有序数组 题目描述 代码 第一种 public void merge(int[] nums1, int m, int[] nums2, int n) {for(int i 0;i<n;i){nums1[mi] nums2[i];}Arrays.sort(nums1);}第二种 public void merge(int[] nums1,…

学习笔记——动态路由——IS-IS中间系统到中间系统(特性之路由泄漏)

3、路由泄漏 什么是路由泄漏&#xff1f; IS-IS路由协议允许路由信息的两级层次结构。可以有多个1级区域通过连续的2级主干互连。路由器可以属于1级、2级或两者。1级链路状态数据库仅包含有关该区域的信息。第2级链路状态数据库包含有关该级别以及每个第1级区域的信息。L1/L2…

【HarmonyOS学习】Calendar Kit日历管理

简介 Calendar Kit提供日历与日程管理能力&#xff0c;包括日历的获取和日程的创建能力。 Calendar Kit为用户提供了一系列接口来获取日历账户&#xff0c;并使用特定的接口向日历账户中写入日程。 如果写入的日程带有提醒时间则系统会在时间到达时向用户发送提醒。 约束点…

解决vue3中el-input在form表单按下回车刷新页面

问题&#xff1a;在input框中点击回车之后不是调用我写的回车事件&#xff0c;而是刷新页面 原因&#xff1a; 如果表单中只有一个input 框则按下回车会直接关闭表单 所以导致刷新页面 解决方法 &#xff1a; 再写一个input 表单 &#xff0c;并设置style"display:none&…

【学习笔记】虚幻SkeletalMesh学习(一)基础介绍

文章目录 零、前言一、资源介绍1.1 骨架资源1.2 骨架网格体资源 二、UE4中的定义2.1 骨骼数据2.2 模型网格数据 三、渲染3.1 RenderData的初始化3.2 渲染对象的创建3.3 渲染对象的更新3.3.1 游戏线程的更新&#xff08;*FSkeletalMeshObjectGPUSkin::Update*&#xff09;3.3.2 …

MSSQL Server运维常用SQL命令

1、数据库连接数 select name, state, state_desc from sys.databases; 查询结果&#xff1a; 2、数据库状态 select name, state, state_desc from sys.databases; 查询结果&#xff1a; 3、数据文件状态 select a.name, b.physical_name, b.state, b.state_desc from sy…

Vue3 组件向下通信 祖孙组件的通信 provide与inject

介绍 当父子间通信可以使用props&#xff0c;祖孙使用provide&#xff08;传递&#xff09;或inject&#xff08;接收&#xff09;&#xff0c; 这时不管组件套的多深都可以向下传递。 例子 现在有一个需求&#xff0c;把App.vue的数据传递到MusciPlay.vue里。 App.vue …

19集 两款ESP32开发板如何选择?-《MCU嵌入式AI开发笔记》

19集 两款ESP32开发板我们用哪款&#xff1f;-《MCU嵌入式AI开发笔记》 有两款ESP32的开发板分别是ESP32 S3 和C3的&#xff0c;我们该如何选择&#xff1f; 1、ESP32-S3-BOX-3 在乐鑫官网上&#xff0c;https://www.espressif.com.cn/zh-hans/products/devkits 有ESP32S3 B…

简约唯美的404HTML源码

源码介绍 简约唯美的404HTML源码,很适合做网站错误页,将下面的源码放到一个空白的html里面,然后上传到服务器里面即可使用 效果预览 完整源码 <!DOCTYPE html> <html><head><meta charset="utf-8"><title>404 Error Example<…

无监督语义分割综述

引言 语义分割是计算机视觉领域的一个重要任务&#xff0c;旨在将图像中的每个像素分配给特定的语义类别。然而&#xff0c;传统的语义分割方法通常依赖大量标注数据&#xff0c;获取这些数据既费时又昂贵。无监督语义分割方法旨在通过不依赖标注数据或仅需少量标注数据的情况…

第11章 规划过程组(四)(11.4规划质量管理)

第11章 规划过程组&#xff08;四&#xff09;11.4规划质量管理&#xff0c;在第三版教材第412~414页&#xff1b; 文字图片音频方式 第一个知识点&#xff1a;工具与技术 1、数据分析&#xff08;重要知识点&#xff09; 成本效益分析 确定质量活动的可能成本与预期效益&a…

景区客流统计系统方便管理者直观地了解客流情况

在当今旅游业蓬勃发展的时代&#xff0c;景区的管理面临着诸多挑战。其中&#xff0c;如何准确、及时地了解客流情况是管理者们关注的重点之一。景区客流统计系统的出现&#xff0c;为解决这一问题提供了高效、便捷的方案&#xff0c;使管理者能够直观地洞察景区内游客的流动态…

探索 Python 的宝藏:深入理解 NumPy库

探索 Python 的宝藏&#xff1a;深入理解 NumPy 库 引言&#xff1a;为何选择 NumPy&#xff1f; NumPy 是 Python 中一个基础而强大的库&#xff0c;它为 Python 语言提供了高性能的多维数组对象和相应的操作。在科学计算、数据分析、机器学习等领域&#xff0c;NumPy 以其高…

Python与MQTT:构建物联网通信的桥梁

&#x1f680;Python与MQTT&#xff1a;构建物联网通信的桥梁&#x1f309; 在这个万物互联的时代&#xff0c;物联网&#xff08;IoT&#xff09;技术正以前所未有的速度改变着我们的生活。从智能家居到智慧城市&#xff0c;从工业自动化到农业智能化&#xff0c;物联网的触角…