AndroidUI--setContentView

我们的Activity通常继承自Activity或者AppCompatActivity,这两个setContentView流程是不同的

一、继承自Activity

在这里插入图片描述

1、Activity.setContentView

在这里插入图片描述
Activity中setContentVIew调用了getWindow().setContentView(view, params);
getWindow返回的是mWindow,mWindow是PhoneWindow对象,在attach中初始化

当创建Activity、Dialog、PopupWindow、Toast时都会创建PhoneWindow对象

在这里插入图片描述

2、PhoneWindow.setContentView

该方法主要目的是创建DecorView 拿到Content
在这里插入图片描述

2.1 installDecor

在installDecor方法中创建DecorView并拿到Content:
在这里插入图片描述
在这里插入图片描述
generateDecor创建DecorView
在这里插入图片描述
generateLayout较长,用于生成和配置窗口(Activity 的视图容器)的布局和样式。
在这里插入图片描述
在这里插入图片描述

上图红框为两行较为重要的代码
onResourcesLoaded是将上面的R.layout.simple等这种layout添加到DecorView中
第二个红框是拿到ViewGroup对象,最后返回的就是这个对象

在这之上,该方法会加载一些layout,以最简单的screen_simple举例

注意:DecorView其实就是个FrameLayout,是整个窗口的根视图,它包括应用程序内容的视图以及窗口可能有的系统级视图,如状态栏和导航栏。

在这里插入图片描述
其中ID为content的FrameLayout就是mContentParent

二、继承自AppCompatActivity

在这里插入图片描述

1、AppCompatActivity.setContentView

在这里插入图片描述
在这里插入图片描述

与继承自Activity的不同,这里是调用的AppCompatDelegate的setContentView
AppCompatDelegate是一个接口,具体实现在AppCompatDelegateImpl:

在这里插入图片描述

1.1、ensureSubDecor

调用ensureSubDecor,下面的与继承Activity的类似
ensureSubDecor又调用createSubDecor

在这里插入图片描述

createSubDecor又调用ensureWindow,ensureWindow是对window对象检查,给mWindow变量赋值,之后执行getDecorView
在这里插入图片描述

此时mWindow是一个PhoneWindow对象,调用PhoneWindow的getDecorView
在这里插入图片描述
getDecorView中又调用了installDecor,这个方法在继承Activity中出现过,此后流程不再赘述

在这里插入图片描述
在这里插入图片描述
crateDecor之后还会去获取subDecor,看最简单的abc_screen_simple
在这里插入图片描述
abc_screen_content_include.xml
在这里插入图片描述
此时subDecor有布局了
之后会通过findViewById去获取上面的ContentFrameLayout
在这里插入图片描述

之后执行final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
在这里插入图片描述
该处获取的是Activity的,也就是R.layout.screen_simple的content
在这里插入图片描述
之后将这个原始的content id置为NO_ID 将subDecerView的id置为content 进行一个替换

三、LayoutInflater.from(mContext).inflate(resId, contentParent);

不管是继承自Activity还是AppCompatActivity的setContentVIew,之后都会调用这么一句代码,该代码就是创建R.layout.main_activity的View
在这里插入图片描述
调用res.getLayout进行xml解析
调用inflate进行渲染

    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {synchronized (mConstructorArgs) {Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");final Context inflaterContext = mContext;final AttributeSet attrs = Xml.asAttributeSet(parser);Context lastContext = (Context) mConstructorArgs[0];mConstructorArgs[0] = inflaterContext;View result = root;try {advanceToRootNode(parser); //寻找根节点final String name = parser.getName(); //节点名称if (DEBUG) {System.out.println("**************************");System.out.println("Creating root view: "+ name);System.out.println("**************************");}//处理merge标签if (TAG_MERGE.equals(name)) {if (root == null || !attachToRoot) {throw new InflateException("<merge /> can be used only with a valid "+ "ViewGroup root and attachToRoot=true");}rInflate(parser, root, inflaterContext, attrs, false);} else {// Temp is the root view that was found in the xml//创建根视图final View temp = createViewFromTag(root, name, inflaterContext, attrs);ViewGroup.LayoutParams params = null;if (root != null) {if (DEBUG) {System.out.println("Creating params from root: " +root);}// Create layout params that match root, if supplied//处理布局参数params = root.generateLayoutParams(attrs);if (!attachToRoot) {// Set the layout params for temp if we are not// attaching. (If we are, we use addView, below)temp.setLayoutParams(params);}}if (DEBUG) {System.out.println("-----> start inflating children");}// Inflate all children under temp against its context.//解析并创建子视图,该方法是一个递归方法rInflateChildren(parser, temp, attrs, true);if (DEBUG) {System.out.println("-----> done inflating children");}// We are supposed to attach all the views we found (int temp)// to root. Do that now.if (root != null && attachToRoot) {root.addView(temp, params);}// Decide whether to return the root that was passed in or the// top view found in xml.if (root == null || !attachToRoot) {result = temp;}}} catch (XmlPullParserException e) {final InflateException ie = new InflateException(e.getMessage(), e);ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;} catch (Exception e) {final InflateException ie = new InflateException(getParserStateDescription(inflaterContext, attrs)+ ": " + e.getMessage(), e);ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;} finally {// Don't retain static reference on context.mConstructorArgs[0] = lastContext;mConstructorArgs[1] = null;Trace.traceEnd(Trace.TRACE_TAG_VIEW);}return result;}}

1、createViewFromTag

在这里插入图片描述
红框中会判断name中是否有点,有执行onCreateView没有执行createView
有点一般的就是一些第三方组件或者自定义组件,比如androidx.constraintlayout.widget.ConstraintLayout

Layoutinflater是一个抽象类,onCreateView的具体实现在其实现类PhoneLayoutInflater
在onCreateView中,最终还是调用了createView
在这里插入图片描述

在这里插入图片描述
此处的prefix是一些前缀,用于在调用createView时进行补全
最后返回了super.onCreateView,父类的onCreateView中补全了android.view
在这里插入图片描述
然后看createView

    @Nullablepublic final View createView(@NonNull Context viewContext, @NonNull String name,@Nullable String prefix, @Nullable AttributeSet attrs)throws ClassNotFoundException, InflateException {Objects.requireNonNull(viewContext);Objects.requireNonNull(name);Constructor<? extends View> constructor = sConstructorMap.get(name);if (constructor != null && !verifyClassLoader(constructor)) {constructor = null;sConstructorMap.remove(name);}Class<? extends View> clazz = null;try {Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);if (constructor == null) {// Class not found in the cache, see if it's real, and try to add it//由于前面补全了前缀,所以这个可以通过包名进行反射,然后创建View对象clazz = Class.forName(prefix != null ? (prefix + name) : name, false,mContext.getClassLoader()).asSubclass(View.class);if (mFilter != null && clazz != null) {boolean allowed = mFilter.onLoadClass(clazz);if (!allowed) {failNotAllowed(name, prefix, viewContext, attrs);}}//获取构造对象constructor = clazz.getConstructor(mConstructorSignature);constructor.setAccessible(true);sConstructorMap.put(name, constructor);} else {// If we have a filter, apply it to cached constructorif (mFilter != null) {// Have we seen this name before?Boolean allowedState = mFilterMap.get(name);if (allowedState == null) {// New class -- remember whether it is allowedclazz = Class.forName(prefix != null ? (prefix + name) : name, false,mContext.getClassLoader()).asSubclass(View.class);boolean allowed = clazz != null && mFilter.onLoadClass(clazz);mFilterMap.put(name, allowed);if (!allowed) {failNotAllowed(name, prefix, viewContext, attrs);}} else if (allowedState.equals(Boolean.FALSE)) {failNotAllowed(name, prefix, viewContext, attrs);}}}Object lastContext = mConstructorArgs[0];mConstructorArgs[0] = viewContext;Object[] args = mConstructorArgs;args[1] = attrs;try {//执行构造,创建View对象final View view = constructor.newInstance(args);if (view instanceof ViewStub) {// Use the same context when inflating ViewStub later.final ViewStub viewStub = (ViewStub) view;viewStub.setLayoutInflater(cloneInContext((Context) args[0]));}return view;} finally {mConstructorArgs[0] = lastContext;}} catch (NoSuchMethodException e) {final InflateException ie = new InflateException(getParserStateDescription(viewContext, attrs)+ ": Error inflating class " + (prefix != null ? (prefix + name) : name), e);ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;} catch (ClassCastException e) {// If loaded class is not a View subclassfinal InflateException ie = new InflateException(getParserStateDescription(viewContext, attrs)+ ": Class is not a View " + (prefix != null ? (prefix + name) : name), e);ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;} catch (ClassNotFoundException e) {// If loadClass fails, we should propagate the exception.throw e;} catch (Exception e) {final InflateException ie = new InflateException(getParserStateDescription(viewContext, attrs) + ": Error inflating class "+ (clazz == null ? "<unknown>" : clazz.getName()), e);ie.setStackTrace(EMPTY_STACK_TRACE);throw ie;} finally {Trace.traceEnd(Trace.TRACE_TAG_VIEW);}}

到这里rootView创建好了,之后要创建子View

2、rInflateChildren

在这里插入图片描述
rInflateChildren调用的是rinflate

    void rInflate(XmlPullParser parser, View parent, Context context,AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {final int depth = parser.getDepth();int type;boolean pendingRequestFocus = false;//循环解析XMLwhile (((type = parser.next()) != XmlPullParser.END_TAG ||parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {//跳过非开始标签if (type != XmlPullParser.START_TAG) {continue;}//获取标签名称final String name = parser.getName();//处理<requestFocus>标签if (TAG_REQUEST_FOCUS.equals(name)) {pendingRequestFocus = true;consumeChildElements(parser);} else if (TAG_TAG.equals(name)) {//处理<tag>标签parseViewTag(parser, parent, attrs);} else if (TAG_INCLUDE.equals(name)) {//处理<include>标签if (parser.getDepth() == 0) {throw new InflateException("<include /> cannot be the root element");}parseInclude(parser, context, parent, attrs);} else if (TAG_MERGE.equals(name)) {//处理<merge>标签throw new InflateException("<merge /> must be the root element");} else {//对于其他标签,使用createViewFromTag创建视图,生成布局参数,递归调用rInflateChildrenfinal View view = createViewFromTag(parent, name, context, attrs);final ViewGroup viewGroup = (ViewGroup) parent;final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);rInflateChildren(parser, view, attrs, true);viewGroup.addView(view, params);}}if (pendingRequestFocus) {parent.restoreDefaultFocus();}if (finishInflate) {parent.onFinishInflate();}}

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

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

相关文章

iOS 中的 UITextField 如何设置才能只输入数字和小数点?

刚接触 iOS不久&#xff0c;接到一个iOS项目&#xff0c;其中有一个需求就是在一个 UITextField中只能输入数字和小数点&#xff0c;这个需求在Android中非常容易&#xff0c;只需要设置 <EditTextandroid:id"id/id_et_price"android:layout_width"match_par…

RedisDesktopManager连接Ubuntu的Redis失败解决办法

配置redis 1.设置redis在后台服务&#xff0c;修改配置文件 默认情况下是 no ,修改为yes&#xff0c;可以后台服务 2、设置redis端口&#xff0c;默认端口是6379&#xff0c;可以根据自己的需要&#xff0c;找到/et/redis/redis.conf文件, 修改port 3、设置密码 配置文件中…

ubuntu20.04“E: 软件包 vim 没有可安装候选”“/etc/apt/sources.list:7 中被配置了多次”解决方法

问题一&#xff1a;ubuntu20.04安装vim时提示“E: 软件包 vim 没有可安装候选” **解决&#xff1a;**更换下载&#xff0c;比如我原先使用的是清华源&#xff0c;后切换成阿里云源&#xff0c;ubuntu直接在“软件和更新”切换 问题一解决。 问题二&#xff1a;ubuntu20.04提…

JavaEE+springboot教学仪器设备管理系统o9b00-springmvc

本文旨在设计一款基于Java技术的教学仪器设备销售网站&#xff0c;以提高网站性能、功能完善、用户体验等方面的优势&#xff0c;解决现有教学仪器设备销售网站的问题&#xff0c;并为广大教育工作者和学生提供便捷的教学仪器设备销售渠道。本文首先介绍了Java技术的相关基础知…

华为昇腾系列——入门学习

概述 昇腾&#xff08;Ascend&#xff09;是华为推出的人工智能处理器品牌&#xff0c;其系列产品包括昇腾910和昇腾310芯片等。 生态情况 众所周知&#xff0c;华为昇腾存在的意义就是替代英伟达的GPU。从事AI开发的小伙伴&#xff0c;应该明白这个替代&#xff0c;不仅仅是…

【自动驾驶坐标系基础】Frenet坐标系和Cartesian坐标系的相互转换

Frenet坐标系和Cartesian坐标系的相互转换 2023.12.12 1 变量含义 Frenet和Cartesian相互转换即 [ s , s ˙ , s , d , d ˙ , d ] ↔ [ X , θ x , κ x , v x , a x ] [s,\dot{s},\ddot{s},d,\dot{d},\ddot{d}] \leftrightarrow[\boldsymbol{X},\theta_x,\kappa_x,v_x,a_…

【Unity开发】【VR】PICO项目在运行编辑器时无法正常显示游戏场景

【背景】 做了一个PICO项目&#xff0c;真机在手边时开发后用PC的Preview模式直接调试&#xff0c;真机不在手边时希望用VRTK的Simulation Rig&#xff0c;用键鼠模拟控制器输入进行快速调试。但是发现Simulation Rig状态下运行后&#xff0c;游戏场景变得很怪&#xff0c;很多…

机器学习之DeepSequence软件使用学习3-预测突变效应

import theano import numpy as np import sys import pandas as pd import scipy from scipy.stats import spearmanr%matplotlib inline import matplotlib.pyplot as plt我们将介绍加载模型和预测突变影响的基本函数。 下载预训练参数。 请首先使用 download_pretrained.s…

计算机软件分类、编程知识体系、编程工作岗位

计算机软件分类、编程知识体系、编程工作岗位 一、计算机软件分类二、计算机语言编程知识体系三、人工智能/机器学习工程师知识体系四、工作岗位 计算机软件分类、计算机编程知识体系、人工智能/机器学习工程师需要掌握的知识体系、计算机语言编程相关工作岗位。存此备查。 一、…

RLT8762D---添加service

0 Preface/Foreword 1 系统初始化LE profile过程 正常开机流程中&#xff0c;gap初始化完成之后&#xff0c;才能进行LE profile初始化。 1.1 添加服务 1.1.1 注册支持服务个数(GATT Server) 函数&#xff1a; server_init 目的&#xff1a;set the number of services th…

MySql缓冲池命中率

缓冲池 大小查看 show variables like innodb_buffer_pool_size; 太小的innodb_buffer_pool_size是不利于性能的提升 命中率查看 一 、 通过以下命令查看相关数据&#xff1a; show global status like Innodb_buffer_pool_read%;结果如下&#xff1a; 命中率公式&#xff1…

已解决com.netflix.client.ClientException Eureka客户端异常的正确解决方法,亲测有效!!!

已解决com.netflix.client.ClientException Eureka客户端异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 出现问题的场景 报错原因 解决思路 解决方法 总结 在微服务架构中&#xff0c;Eureka作为服务发现组件&#xff0c;…

SpringBoot集成mail

发送邮件&#xff1a;SMPT、MIME&#xff0c;是一种基于"推"的协议&#xff0c;通过SMPT协议将邮件发送至邮件服务器&#xff0c;MIME协议是对SMPT协议的一种补充&#xff0c;如发送图片附件等 接收邮件&#xff1a;POP、IMAP&#xff0c;是一种基于"拉"的…

Zabbix监控容器MongoDB,报错:Unknown metric mongodb.server.status

在Zabbix中配置监控MongoDB容器时&#xff0c;如果遇到Unknown metric mongodb.server.status这样的错误&#xff0c;通常意味着Zabbix Agent尝试从MongoDB获取某个预定义的性能指标&#xff08;例如mongodb.server.status&#xff09;&#xff0c;但是未能成功识别或解析该指标…

GPT4+Python近红外光谱数据分析及机器学习与深度学习建模教程

原文链接&#xff1a;GPT4Python近红外光谱数据分析及机器学习与深度学习建模教程 第一&#xff1a;GPT4 1、ChatGPT&#xff08;GPT-1、GPT-2、GPT-3、GPT-3.5、GPT-4模型的演变&#xff09; 2、ChatGPT对话初体验 3、GPT-4与GPT-3.5的区别&#xff0c;以及与国内大语言模…

简易版axios实现-基于promise+XMLHttpRequest

/*** 目标&#xff1a;封装_简易axios函数_获取省份列表* 1. 定义myAxios函数&#xff0c;接收配置对象&#xff0c;返回Promise对象* 2. 发起XHR请求&#xff0c;默认请求方法为GET* 3. 调用成功/失败的处理程序* 4. 使用myAxios函数&#xff0c;获取省份列表展示*/functi…

[数据集][目标检测]芒果叶病害数据集VOC+YOLO格式4000张5类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4000 标注数量(xml文件个数)&#xff1a;4000 标注数量(txt文件个数)&#xff1a;4000 标注…

微信小程序开发系列(十六)·事件传参·data-*自定义数据

事件传参&#xff1a;在触发事件时,将一些数据作为参数传递给事件处理函数的过程,就是事件传参。 在微信小程序中,我们经常会在组件上添加一些自定义数据,然后在事件处理函数中获取这些自定义数据,从而完成业务逻辑的开发。 在组件上通过data-"的方式定义需要传递的数据,其…

Android14之解决编译报错:bazel: no such file or directory(一百八十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

赢在起跑线:商品企划系统为鞋服品牌带来的竞争优势解析

在鞋服行业的激烈竞争中&#xff0c;每个品牌都渴望在市场中脱颖而出&#xff0c;而成功的起点往往在于商品企划的策略制定。商品企划系统作为一种先进的商业策略工具&#xff0c;能够帮助鞋服品牌赢在起跑线&#xff0c;获得竞争优势。本文将深入探讨商品企划系统如何为鞋服品…