Activity中Window与View的关系

本文主要记录在Activity中View与Window相互作用关系,以及如何管理Window的展示、删除和更新。

创建Window

ActivityThread收到launchActivity消息后,会调用performLaunchActivity方法开始创建Activity相关流程

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {//***准备工作//创建ContextImpl对象ContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();/反射创建Activity对象activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);//****try {//如果当前进程application为null,则会创建application并调用attachBaseContext,onCreate等方法Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (activity != null) {Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {window = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;}appContext.setOuterContext(activity);//调用activity的attach方法,此时window参数是nullactivity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback,r.assistToken, r.shareableActivityToken);if (customIntent != null) {activity.mIntent = customIntent;}//回调onCreate方法,在该方法中会将业务View加载到decorview中if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}//****return activity;}

创建activity后,回调activity的attach方法,window就在这个方法中创建

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) {//调用activity的attachBaseContext方法attachBaseContext(context);mFragments.attachHost(null /*parent*/);//这里创建PhoneWindow对象,该对象就是window的实现类mWindow = new PhoneWindow(this, window, activityConfigCallback);mWindow.setWindowControllerCallback(mWindowControllerCallback);//activity本身就是window的callback实现者,这里设置给window来接收window相关的事件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);}//****省略一些赋值操作//获取WindowManager,实际是WindowManagerGlobal对象,mWindowManager = mWindow.getWindowManager();//**** }

上述可知,activity的window对象是在attch方法中创建,其是PhoneWindow的实例。

添加View

添加View到window上主要在ActivityThread的handleResumeActivity方法中

public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,boolean isForward, String reason) {//分发OnResume方法if (!performResumeActivity(r, finalStateRequest, reason)) {return;}final Activity a = r.activity;boolean willBeVisible = !a.mStartedActivity;if (!willBeVisible) {willBeVisible = ActivityClient.getInstance().willActivityBeVisible(a.getActivityToken());}if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();//*****if (a.mVisibleFromClient) {if (!a.mWindowAdded) {a.mWindowAdded = true;//调用WindowManager的addView方法wm.addView(decor, l);} else {//*****}}//**r.activity.mVisibleFromServer = true;mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {//调用Activity的makeVisible方法展示内容r.activity.makeVisible();}}

上述代码可以发现,在onresume的流程中会调用WindowManagerglobal的addView方法添加View

    //WindowManagerGlobal成员变量, 每个窗口的根View,数量和Window 1:1private final ArrayList<View> mViews = new ArrayList<View>();//WindowManagerGlobal成员变量, 每个窗口的根View和window的连接器,数量和Window 1:1private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();//WindowManagerGlobal成员变量, 每个窗口的参数,数量和Window 1:1private final ArrayList<WindowManager.LayoutParams> mParams =new ArrayList<WindowManager.LayoutParams>();//WindowManagerGlobal成员变量, 当前正在移除的Viewprivate final ArraySet<View> mDyingViews = new ArraySet<View>();public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow, int userId) {//参数校验ViewRootImpl root;View panelParentView = null;synchronized (mLock) {//创建ViewRootImpl对象root = new ViewRootImpl(view.getContext(), display);view.setLayoutParams(wparams);///将view,root,和窗口参数添加到集合中,标记着一个Window被记录了mViews.add(view);mRoots.add(root);mParams.add(wparams);try {//调用root的setView方法root.setView(view, wparams, panelParentView, userId);} catch (RuntimeException e) {}}}

展示View

接下来分析setView相关的流程

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,int userId) {synchronized (this) {if (mView == null) {mView = view;//绑定view和AttachInfomAttachInfo.mRootView = view;mAdded = true;int res; /* = WindowManagerImpl.ADD_OKAY; *///请求测量/布局/绘制requestLayout();try {//在WMS中创建一个与Window相关的对象,WMS管理所有的Window的层级、位置、大小res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(), userId,mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,mTempControls);} //***setFrame(mTmpFrames.frame);//绑定View和ViewRootImplview.assignParent(this);}}}

由上述可以知道,setView方法主要做两件大事:1.将View和ViewRootImpl绑定后开启View绘制请求(requestLayout),并通过IPC请求WMS创建Surface,2.通过WindowSession进行IPC调用给WMS中创建一个与Window相关的对象,然后WMS管理所有的Window的层级、位置、大小。应用端在WMS分配Surface的绘制完成,SurfaceFlinger会把这些Surface图像数据按WMS中的层级、位置、大小等进行合成,最终写屏幕的缓冲区显示出来。详细的流程可以查看performTraversals方法

private void performTraversals() {//通过IPC创建&申请SurfacerelayoutResult = relayoutWindow(params, viewVisibility, insetsPending);performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);performLayout(lp, mWidth, mHeight);performDraw();}

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

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

相关文章

服务器“雪崩”的常见原因和解决方法 (C++)

在C服务器编程中&#xff0c;"雪崩"现象指的是服务器在高并发请求的情况下&#xff0c;由于资源&#xff08;如线程、文件描述符、内存等&#xff09;耗尽或锁争用等问题&#xff0c;导致服务器性能急剧下降&#xff0c;甚至完全失去响应的情况。这种现象会连带影响其…

Redis持久化(RDB、AOF)详解

Redis持久化详解 一、Redis为什么需要持久化&#xff1f; Redis 是一个基于内存的数据库&#xff0c;拥有极高的读写性能&#xff0c;但是内存中的数据在断电或服务器重启时会全部丢失&#xff0c;因此需要一种持久化机制来将数据保存到硬盘上&#xff0c;以便在需要时进行恢复…

华为数通——STP-RSTP-MSTP生成树

STP 为了提高网络可靠性&#xff0c;交换机之间常常会进行设备冗余&#xff08;备份&#xff09;&#xff0c;但这样会给交换网络带来环路风险&#xff0c;导致广播风暴以及MAC地址表不稳定等问题。 STP&#xff1a;生成树协议的作用就是为了解决避免二层环路&#xff0c;解决…

STM32 DAC模块的应用(FW_F1_V1.8.5)

目录 概述 1 STM32Cube配置项目 1.1 软件版本信息 1.2 配置DAC模块参数 1.3 GENERATE Project 2 DAC库函数介绍 2.1 初始化函数&#xff1a;HAL_DAC_Init 2.2 启动DAC数据转换&#xff1a;HAL_DAC_Start 2.3 停止DAC数据转换&#xff1a;HAL_DAC_Stop 2.4 设置通道数…

CentOS停止维护,如何应对?

一、事件背景 2020年12月08日&#xff0c;CentOS官方宣布了停止维护CentOS Linux的计划&#xff0c;并推出了CentOS Stream项目。 更多信息&#xff0c;请参见CentOS官方公告。 版本变化说明CentOS 9不再支持新的软件和补丁更新CentOS 82021年12月31日停止维护服务CentOS 720…

小程序中data-xx是用方式

data-sts"3" 是微信小程序中的一种数据绑定语法&#xff0c;用于在 WXML&#xff08;小程序模板&#xff09;中将自定义的数据绑定到页面元素上。让我详细解释一下&#xff1a; data-xx 的作用&#xff1a; data-xx 允许你在页面元素上自定义属性&#xff0c;以便在事…

【征服数据结构】:期末通关秘籍

【征服数据结构】&#xff1a;期末通关秘籍 &#x1f498; 数据结构的基本概念&#x1f608; 数据结构的基本概念&#x1f608; 逻辑结构和存储结构的区别和联系&#x1f608; 算法及其特性&#x1f608; 简答题 &#x1f498; 线性表&#xff08;链表、单链表&#xff09;&…

HTML5【新特性总结】

HTML5【新特性总结】 HTML5 的新增特性主要是针对于以前的不足&#xff0c;增加了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题&#xff0c;基本是 IE9 以上版本的浏览器才支持&#xff0c;如果不考虑兼容性问题&#xff0c;可以大量使用这些新特性。…

小牛G0 60拆机

日常通勤的GOVA G0 60 的后刹车线断了&#xff0c;需要自已换刹车线&#xff0c;翻阅网上的资料后&#xff0c;可能该条刹车线需要全部拆解&#xff0c;因此开贴记录 应该不用全拆&#xff0c;但是如上图&#xff0c;后刹车线有2条绑带&#xff0c;因此更换要拆到这个位置。 1…

NAT、SNAT与DNAT详解

一、概述 NAT&#xff08;Network Address Translation&#xff09;&#xff0c;即网络地址转换&#xff0c;是一种在IP数据包通过路由器或防火墙时修改其源或目标IP地址的技术。NAT技术的出现主要是为了解决IPv4地址短缺的问题&#xff0c;并增加网络的安全性。通过NAT&#x…

前端 CSS 经典:保持元素宽高比

前言&#xff1a;在很多网站&#xff0c;不管页面宽度的变化&#xff0c;都需要里面的图片或者视频&#xff0c;宽高比不变。有两种实现方式。 1. aspect-ratio 属性 使用 aspect-ratio 属性可以直接定义元素的宽高比&#xff0c;但是有兼容性问题 <!DOCTYPE html> &l…

Hi3861 OpenHarmony嵌入式应用入门--LiteOS Event

CMSIS 2.0接口使用事件标志是实时操作系统&#xff08;RTOS&#xff09;中一种重要的同步机制。事件标志是一种轻量级的同步原语&#xff0c;用于任务间或中断服务程序&#xff08;ISR&#xff09;之间的通信。 每个事件标志对象可以包含多个标志位&#xff0c;通常最多为31个&…

SpringBoot条件注解原理

SpringBoot条件注解原理 文章目录 SpringBoot条件注解原理关于Spring Framework中的Conditional关于SpringBootCondition(所有SpringBoot条件注解的根)关于ConditionalOnClass关于OnClassCondition如果判断某个类不存在,filter方法 SpringBoot封装了很多基于Spring Framework中…

军用FPGA软件 Verilog语言的编码准测之三态缓冲器和运算符

军用FPGA软件 Verilog语言的编码准测之三态缓冲器和运算符 语言 &#xff1a;Verilg HDL EDA工具&#xff1a;ISE、Vivado、Quartus II 军用FPGA软件 Verilog语言的编码准测之三态缓冲器和运算符一、引言二、基本编程规范之三态缓冲器强制准则1---禁止组合逻辑电路的输出作为三…

CSS justify-content 不生效的原因 失效

MDN文档&#xff1a; https://developer.mozilla.org/zh-CN/docs/Web/CSS/justify-content CSS justify-content 属性定义浏览器如何沿着弹性容器的主轴和网格容器的行向轴分配内容元素之间和周围的空间。 justify-content什么情况下会不生效&#xff08;失效&#xff09;&a…

在码云(Gitee)上建立分支(Branch)的步骤如下:

步骤一&#xff1a;登录码云 首先&#xff0c;打开码云的官方网站&#xff08;gitee.com&#xff09;&#xff0c;输入用户名和密码登录你的账号。 步骤二&#xff1a;创建仓库 登录后&#xff0c;在页面右上方的搜索框中输入仓库名称&#xff0c;并点击“创建”按钮创建新的仓…

API-表单全选反选案例

学习目标&#xff1a; 掌握表单全选反选案例 学习内容&#xff1a; 案例css伪类选择器checked 案例&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"…

《看不影子的少年》一部探讨偏见与接纳的电视剧❗

《看不见影子的少年》这部电视剧以其独特的视角和深刻的主题 给我留下了深刻的印象。该剧讲述了一位与众不同的少年 他无法在阳光下留下影子&#xff0c;象征着他在社会中的孤独与不被理解 观看过程中&#xff0c;可以感受到少年内心的挣扎与渴望 他渴望被接纳&#xff0c;渴…

APM教程-SkyWalking安装和配置

SkyWalking简介 APM (Application Performance Management) 即应用性能管理&#xff0c;属于IT运维管理&#xff08;ITOM)范畴。主要是针对企业 关键业务的IT应用性能和用户体验的监测、优化&#xff0c;提高企业IT应用的可靠性和质量&#xff0c;保证用户得到良好的服务&#…

Java如何设置Map过期时间的的几种方法

一、技术背景 在实际的项目开发中&#xff0c;我们经常会使用到缓存中间件&#xff08;如redis、MemCache等&#xff09;来帮助我们提高系统的可用性和健壮性。 但是很多时候如果项目比较简单&#xff0c;就没有必要为了使用缓存而专门引入Redis等等中间件来加重系统的复杂性…