当前位置: 首页 > news >正文

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();}}

相关文章:

AndroidUI--setContentView

我们的Activity通常继承自Activity或者AppCompatActivity&#xff0c;这两个setContentView流程是不同的 一、继承自Activity 1、Activity.setContentView Activity中setContentVIew调用了getWindow().setContentView(view, params); getWindow返回的是mWindow&#xff0c;mWi…...

编程笔记 Golang基础 047 mysql数据库连接与操作

编程笔记 Golang基础 047 mysql数据库连接与操作 一、连接与操作1. 安装MySQL驱动2. 导入驱动包3. 连接数据库4. 执行SQL查询和操作5. 使用连接池6. 处理事务 二、连接字符串三、应用示例四、比较 MySQL凭借其开源、高效、稳定、灵活、安全以及广泛的社区支持等诸多优势&#x…...

.jsonl 格式文件的解释

根据 CHATGPT .jsonl 文件格式是一种文本文件格式&#xff0c;通常用于存储每行一个JSON对象的数据。.jsonl 文件的每一行都是一个独立的JSON对象&#xff0c;这些对象之间没有任何分隔符。 以下是一个示例.jsonl文件的内容&#xff1a; {"name": "John"…...

nodejs web服务器 -- 搭建开发环境

一、配置目录结构 1、使用npm生成package.json&#xff0c;我创建了一个nodejs_network 文件夹&#xff0c;cd到这个文件夹下&#xff0c;执行&#xff1a; npm init -y 其中-y的含义是yes的意思&#xff0c;在init的时候省去了敲回车的步骤&#xff0c;如此就生成了默认的pac…...

laravel-admin 头部添加操作

新建html 样式及js namespace App\Admin\Extensions\Nav;class Links {public function __toString(){return <<<HTML<li><a href"" οnclick"js_method();return false;"><i class"fa fa-floppy-o"></i><s…...

mysql笔记:10. 日志

文章目录 一、日志概述二、错误日志1. 启动2. 查看3. 删除 三、二进制日志1. 启动2. 查看3. 删除 四、通用查询日志1. 启动2. 查看3. 删除 五、慢查询日志1. 启动2. 查看3. 删除 日志是MySQL数据库的重要组成部分&#xff0c;日志文件中记录着MySQL数据库运行期间发生的变化。M…...

代码随想录刷题笔记-Day32

1. 最大子序和 53. 最大子数组和https://leetcode.cn/problems/maximum-subarray/ 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组&#xff1a;是数组中的一个连续…...

指针的学习5

目录 sizeof和strlen的区别 sizeof strlen 数组和指针笔试题解析 一维数组 字符数组 二维数组 指针运算笔试题解析 题目1&#xff1a; 题目2&#xff1a; 题目3&#xff1a; 题目4&#xff1a; 题目5&#xff1a; 题目6&#xff1a; 题目7&#xff1a; sizeof和…...

Dynamo——常用几何形体的创建与编辑(二)

上一次&#xff0c;我们简单整理了一些创建几何形体的节点用法&#xff0c;今天我们接着整理一些&#xff0c;几何形体的编辑方法。 一、坐标点的平移复制 [Point.Add] 使用节点 “Vector.ByCoordinates” 生成一个向量&#xff0c;将该向量连接到 “Point.Add” 节点的输入端 …...

uniapp富文本编辑-editor-vue2-vue3-wangeditor

前言 不管vue2还是vue3&#xff0c;都推荐官方的editor组件, 官方手册 https://uniapp.dcloud.net.cn/component/editor.html除了“微信小程序”&#xff0c;其他小程序想要使用editor组件实现富文本编辑&#xff0c;很难 ​​​​​​​第三方组件wangeditor在vue2&#xff0…...

【java】22:try-catch 异常处理

try-catch 方式处理异常说明 public static void main(String[] args) { int num1 10; int num2 0; try { int res num1 / num2; } catch (Exception e) { System.out.println(e.getMessage()); } } 注意事项 1)如果异常发生了&#xff0c;则异常发生后面的代码不会执行&…...

【C语言】linux内核ip_local_out函数

一、讲解 这个函数 __ip_local_out 是 Linux 内核网络子系统中的函数&#xff0c;部分与本地出口的 IPv4 数据包发送相关。下面讲解这段代码的每一部分&#xff1a; 1. 函数声明 int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)&#xff1a; -…...

动态规划6,最大数组和,环形子数组最大和,乘积最大子数组

最大子数组和 思路&#xff1a; 1.经验题目要求 dp[i]表示&#xff1a;以 i 位置为结尾的所有子数组中的最大和 2.状态转移方程 按长度来划分&#xff0c;如果长度为1&#xff0c;那么dp[i] nums[i]; 如果长度大于1&#xff0c;那么当前位置的最大和就为 i-1 位置最大和 …...

js 清空数组的方法

1、直接赋值空数组 let array [1, 2, 3, 4, 5]; array []; 这种方法并不推荐&#xff0c;如下图所示&#xff1a; 虽然a数组确实变为了空数组&#xff0c;但这种方法只是修改了a的指向&#xff0c;把a指向一个新的空数组&#xff0c;然而[1,2,3,4,5]这个数组并没有被清除&a…...

QT中使用QProcess执行命令,实时获取数据,例如进度条

前言 因为之前写了一个接收和发送文件的脚本&#xff0c;然后又需要获取进度&#xff0c;同步到进度条中。 效果&#xff1a; 使用正则匹配&#xff0c;获取命令行命令中的以下数据&#xff0c;然后同步到进度条 源码demo&#xff1a; 非完整代码&#xff1a; #include <Q…...

绘图设计:用Draw.io绘制图形技巧大全(含统一建模语言UML模板)

一、常见UML模板 1.流程图 2.用例图 include是包含关系&#xff0c;extend是扩展关系 简而言之&#xff0c;include是子集指向父集&#xff1b;而extend是扩展用例指向基础用例&#xff08;基础用例可以理解为系统核心功能&#xff0c;扩展用例是可选的&#xff0c;不是必须…...

被唤醒的“第二十条”深入人心

近来张艺谋执导的电影《第二十条》&#xff0c;因为它与正在召开中的全国两会所发布的《最高人民法院工作报告》联系相当紧密&#xff0c;加之可免费收看&#xff0c;网民便相互转告&#xff0c;于是此信息条目立即冲上了网络热搜榜&#xff0c;观者如潮。因为最高人民法院工作…...

PHPInfo()信息泄漏原理以及修复方法

漏洞名称&#xff1a;PHPInfo信息泄漏、phpinfo()函数信息泄漏 漏洞描述&#xff1a; phpinfo()函数返回的信息中包含了服务器的配置信息&#xff0c;包括&#xff1a; 1&#xff09;PHP编译选项以及文件扩展名的相关信息&#xff1b; 2&#xff09;php的版本信息 3&#…...

202441读书笔记|《笠翁对韵》—— 金菡萏,玉芙蓉,酒晕微酡琼杏颊,香尘浅印玉莲双

202441读书笔记|《笠翁对韵》——金菡萏&#xff0c;玉芙蓉&#xff0c;酒晕微酡琼杏颊&#xff0c;香尘浅印玉莲双 《作家榜名著&#xff1a;笠翁对韵》作者李渔&#xff0c;霍俊明。是所有词句都有注音的一本书&#xff0c;轻松学不认识的字&#xff0c;非常朗朗上口的对偶词…...

006-v-model原理

v-model原理 简介v-model应用在输入框上v-model应用在组件上 简介 由 属性绑定(v-bind:value“searchText”) 配合 input事件监听(v-on:input“searchText event.target.value”) 实现。 应用在组件上由 props: {value: xxx } &#xff0c;this.$emit(‘input’, xxx ) 完成。…...

二手交易|基于springboot + vue二手交易管理系统(源码+数据库+文档)

二手交易管理系统 目录 基于springboot vue二手交易管理系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue二手交易管理系统 一、前言 博主介绍&am…...

从源码到实战:手把手教你编译与定制化iperf网络性能测试工具

1. iperf工具简介与适用场景 iperf是一款经典的开源网络性能测试工具&#xff0c;它通过测量TCP/UDP带宽来评估网络质量。我第一次接触这个工具是在调试嵌入式设备的网络吞吐量时&#xff0c;当时需要验证百兆网口的实际传输速率是否达标。相比简单的ping命令&#xff0c;iperf…...

从滤波到优化:手把手拆解VIO算法核心,看懂OpenVINS的MSCKF和ORB-SLAM3的BA到底差在哪

从滤波到优化&#xff1a;手把手拆解VIO算法核心&#xff0c;看懂OpenVINS的MSCKF和ORB-SLAM3的BA到底差在哪 视觉惯性里程计&#xff08;VIO&#xff09;技术近年来在机器人导航、增强现实等领域展现出强大的生命力。对于开发者而言&#xff0c;理解不同技术流派的核心差异&am…...

如何用 cookie 的 HttpOnly 与 Secure 属性防范 XSS 攻击

HttpOnly 和 Secure 属性协同防护 Cookie&#xff1a;HttpOnly 禁止 JavaScript 读取 Cookie 防 XSS 窃取&#xff0c;Secure 强制仅 HTTPS 传输防 MITM 截获&#xff1b;二者必须同时启用&#xff0c;并配合 SameSite&#xff08;Lax/Strict&#xff09;增强安全。HttpOnly 和…...

020、总结与实战项目:手把手打造你的个性化语音助手

上周调试语音唤醒模块,半夜被一段合成音频吓得不轻——本该说“早上好”的TTS,硬生生念成了“造上好”,每个字都像用刀切出来的,机械感十足。那一刻我意识到,很多开发者把TTS当成黑盒调用,直到实际产品落地时才被发音质量、延迟、资源占用等问题打得措手不及。今天我们就…...

用Python搞定FEMTO-ST轴承数据集的完整处理流程(附Matlab代码对比)

Python与Matlab双视角解析FEMTO-ST轴承数据集处理实战 轴承健康监测是工业预测性维护的核心场景之一。FEMTO-ST研究所发布的IEEE PHM 2012挑战赛数据集&#xff0c;作为该领域的基准测试数据&#xff0c;包含了轴承全寿命周期的高频振动与温度监测记录。对于刚接触该数据集的研…...

别只扫二维码!MISC隐写术实战:用Stegsolve和010Editor破解ISCC‘美人计’全流程

从二维码到密钥&#xff1a;深度解析MISC隐写术实战框架 在网络安全竞赛的MISC&#xff08;杂项&#xff09;题目中&#xff0c;隐写术往往是最考验选手综合能力的题型之一。不同于常规的漏洞利用或密码破解&#xff0c;隐写术题目通常需要选手具备敏锐的观察力、多工具协同能力…...

深度学习实战:基于TextCNN的新闻分类模型构建与调优全解析

1. TextCNN新闻分类模型的核心原理 TextCNN作为卷积神经网络在文本领域的经典应用&#xff0c;其核心思想是将图像处理中的卷积操作迁移到文本序列上。想象一下&#xff0c;我们用不同尺寸的筛子&#xff08;卷积核&#xff09;在文本上滑动&#xff0c;每个筛子都能捕捉特定长…...

微信小程序Canvas实战:5分钟实现图片自由拖拽+缩放旋转(附完整代码)

微信小程序Canvas进阶&#xff1a;打造高互动性图片编辑器 在移动互联网时代&#xff0c;图片编辑已成为社交分享的刚需功能。微信小程序凭借其轻量级特性&#xff0c;结合Canvas的强大绘图能力&#xff0c;为开发者提供了实现复杂图片交互的可能。本文将带你从零构建一个支持拖…...

从踩坑到精通:Element el-date-picker 与后端 API 联调的那些‘坑’和最佳实践

从踩坑到精通&#xff1a;Element el-date-picker 与后端 API 联调实战指南 在前后端分离的开发模式中&#xff0c;日期选择器作为高频交互组件&#xff0c;其与后端的数据对接往往成为初级开发者的"隐形杀手"。Element UI 的 el-date-picker 组件虽然功能强大&#…...