LayoutInflater加载流程
简介
LayoutInflater在日常的Android开发中是经常使用的类,常常用于XML中View的加载相关流程。本文主要总结一些其常见api的源码流程。
获取LayoutInflater
我们一般会在Activity的onCreate方法中会通过setContentView方法设置自己的布局layoutId,Activity会将加载View委托给Window。
public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);initWindowDecorActionBar();}public LayoutInflater getLayoutInflater() {return getWindow().getLayoutInflater();}
而Window对应的实现是PhoneWindow类
@Overridepublic void setContentView(int layoutResID) {if (mContentParent == null) {installDecor();} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}*****省略部分代码mLayoutInflater.inflate(layoutResID, mContentParent);}public PhoneWindow(@UiContext Context context) {super(context);mLayoutInflater = LayoutInflater.from(context);****省略部分代码}
从上述可知activity中的相关inflater来自PhoneWindow,其本质来自 LayoutInflater.from(context)
Factory和Factory2
Factory和Factory2是两个接口,用户创建具体的View对象,Factory2继承自Factory,新增了onCreateView 重载API,该api新增了parent参数。
public interface Factory {@NullableView onCreateView(@NonNull String name, @NonNull Context context,@NonNull AttributeSet attrs);}public interface Factory2 extends Factory {@NullableView onCreateView(@Nullable View parent, @NonNull String name,@NonNull Context context, @NonNull AttributeSet attrs);}
上述两个接口主要用在LayoutInflater类inflater()流程中,其中解析xml获取到对应的view描述信息后,调用tryCreateView去创建View。
public abstract class LayoutInflater {@UnsupportedAppUsageprivate Factory mFactory;@UnsupportedAppUsageprivate Factory2 mFactory2;@UnsupportedAppUsageprivate Factory2 mPrivateFactory;View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,boolean ignoreThemeAttr) {//*****省略try {View view = tryCreateView(parent, name, context, attrs);if (view == null) {final Object lastContext = mConstructorArgs[0];mConstructorArgs[0] = context;try {if (-1 == name.indexOf('.')) {view = onCreateView(context, parent, name, attrs);} else {view = createView(context, name, null, attrs);}} finally {mConstructorArgs[0] = lastContext;}}return view;//****}public final View tryCreateView(@Nullable View parent, @NonNull String name,@NonNull Context context,@NonNull AttributeSet attrs) {//*****View view;if (mFactory2 != null) {view = mFactory2.onCreateView(parent, name, context, attrs);} else if (mFactory != null) {view = mFactory.onCreateView(name, context, attrs);} else {view = null;}if (view == null && mPrivateFactory != null) {view = mPrivateFactory.onCreateView(parent, name, context, attrs);}return view;}
可以看到,在tryCreateView中会按优先级去调用对应Factory的onCreateView方法去获取View实例,如果该方法返回空,则createViewFromTag方法会调用layoutInflater的onCreateView方法去创建View。该方法会反射创建View对象。
LayoutInflater中设计的Factory和Factory2相关接口和类,给了开发者自定义View创建和适配的机会。比如应用换肤、framework的View替换等。比如包含TextView的xml设置给AppCompatActivity时,其TextView会被替换成AppCompatTextView。
inflate流程
我们一般使用layoutInflater对象的inflater方法来加载xml中的View。该方法需要关注root和attachToRoot参数,root表示当前待加载的View的父容器。该参数对加载的影响主要是父容器的尺寸和主题对当前View的效果影响。而attachToRoot表示是否将当前待加载的View添加到父容器中,这个还会影响inflate方法返回值,当attachToRoot=true,返回父容器,attachToRoot=false返回当前加载到View。
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {return inflate(resource, root, root != null);}public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {return inflate(parser, root, root != null);}public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {final Resources res = getContext().getResources();//如果是预编译的View,则反射创建该View。这里的预编译是指在打包时将xml描述的布局编译成.CompiledView文件。这样创建时不用解析xml。默认预编译为关闭状态View view = tryInflatePrecompiled(resource, res, root, attachToRoot);if (view != null) {return view;}XmlResourceParser parser = res.getLayout(resource);try {return inflate(parser, root, attachToRoot);} finally {parser.close();}}public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {synchronized (mConstructorArgs) {try {advanceToRootNode(parser);final String name = parser.getName();if (TAG_MERGE.equals(name)) {//merge标签时,root必须非NULL,并且attachToRoot必须为true。因为meger标签本身没有parent,无法正确加载。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 {// 根据name创建对应的View,前文我们有提到这个方法final View temp = createViewFromTag(root, name, inflaterContext, attrs);ViewGroup.LayoutParams params = null;if (root != null) {//生成paramsparams = 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);}}// 加载当前节点的子ViewrInflateChildren(parser, temp, attrs, true);// 如果root不为空并且attachToRoot=true,则把当前加载View添加到root中if (root != null && attachToRoot) {root.addView(temp, params);}//result为返回值,这里root == null || !attachToRoot时返回值时当前View,否则是rootif (root == null || !attachToRoot) {result = temp;}}} //***省略***return result;}}
LayoutInflater创建View
前文我们分析createViewFromTag这个方法时提到,如果factory和factory2创建View时都返回了Null,那么会兜底走LayoutInflater的onCreateView方法,该方法最终会调用createView创建View。我们来看看View是是不是通过反射创建的。
public final View createView(@NonNull Context viewContext, @NonNull String name,@Nullable String prefix, @Nullable AttributeSet attrs)throws ClassNotFoundException, InflateException {//*******Class<? extends View> clazz = null;try {if (constructor == null) {// Class not found in the cache, see if it's real, and try to add it//****//获取View的构造函数并缓存,这样不用每次都去查constructor = clazz.getConstructor(mConstructorSignature);constructor.setAccessible(true);sConstructorMap.put(name, constructor);}//****省略部分代码Object lastContext = mConstructorArgs[0];mConstructorArgs[0] = viewContext;Object[] args = mConstructorArgs;args[1] = attrs;try {//反射创建Viewfinal View view = constructor.newInstance(args);if (view instanceof ViewStub) {//如果是ViewStub,则设置LayoutInflater给它final ViewStub viewStub = (ViewStub) view;viewStub.setLayoutInflater(cloneInContext((Context) args[0]));}return view;} finally {mConstructorArgs[0] = lastContext;}} //***}
相关文章:
LayoutInflater加载流程
简介 LayoutInflater在日常的Android开发中是经常使用的类,常常用于XML中View的加载相关流程。本文主要总结一些其常见api的源码流程。 获取LayoutInflater 我们一般会在Activity的onCreate方法中会通过setContentView方法设置自己的布局layoutId,Act…...
PLC数据采集案例
--------天津三石峰科技案例分享 项目介绍 项目背景 本项目为天津某钢铁集团下数字化改造项目,主要解决天津大型钢厂加氢站数字化改造过程中遇到的数据采集需求。项目难点PLC已经在运行了,需要采集里面数据,不修改程序,不影响P…...
基于单片机和LabVIEW 的远程矿井水位监控系统设计
摘要 : 针 对 现 有 矿 井 水 位 监 控 系 统 存 在 结 构 复 杂 和 不 能 远 程 监 控 的 问 题 , 设计了基于单片机和LabVIEW 的远程矿井水位监控系统 , 详…...
element 表格嵌套表单验证指定行
elementui表格嵌套动态表单,单独验证某一行输入项是否符合校验规则; input动态绑定校验 :prop"imgTable. scope.$index .bxName" <el-form :model"formTable" ref"formTable" inline size"small"><…...
CORE Mobility Errorr的调试
在运行CORE tutorial 3中的mobility示例时,出现如下错误: 当看到这个问题的时候,并没有仔细去分析日志和现象,在core-daemon的进程打印界面只看了一下最后的出错堆栈: 2024-06-27 10:43:48,614 - ERROR - _server:_ca…...
基于weixin小程序乡村旅游系统的设计
管理员账户功能包括:系统首页,个人中心,用户管理,商家管理,旅游景点管理,景点类型管理,景点路线管理,系统管理 商家帐号账号功能包括:系统首页,旅游景点管理&…...
详解三种常用标准化 Batch Norm Layer Norm RMSNorm
参考: BN究竟起了什么作用?一个闭门造车的分析《动手学深度学习》7.5 节 深度学习中,归一化是常用的稳定训练的手段,CV 中常用 Batch Norm; Transformer 类模型中常用 layer norm,而 RMSNorm 是近期很流行…...
云计算运维工程师面试
1. 云计算运维工程师的角色和职责是什么? 回答: 云计算运维工程师负责确保云计算环境(包括硬件和软件系统)的高可用性和稳定性。他们的主要职责包括: 监测系统和应用程序的性能,确保它们正常运行。故障排除,快速响应并解决系统或应用程序中出现的问题。容量规划,根据…...
聚观早报 | iPhone 16核心硬件曝光;三星Galaxy全球新品发布会
聚观早报每日整理最值得关注的行业重点事件,帮助大家及时了解最新行业动态,每日读报,就读聚观365资讯简报。 整理丨Cutie 6月28日消息 iPhone 16核心硬件曝光 三星Galaxy全球新品发布会 苹果正多方下注布局AI商店 黄仁勋2024年薪酬3400…...
web前端之文档流、浮动、定位详解
目录 一、文档流 二、浮动 1.添加浮动 2.清除浮动 三、定位 1.相对定位 2.绝对定位 一、文档流 什么是文档流? ● 文档流指的是文档中的标签在排列时所占用的位置。 将窗体自上而下分成一行行 ,并在每 行中按从左至右的顺序排放标签,…...
[JS]节点操作
DOM节点 DOM树中的所有内容都是节点, 我们重点关注元素节点 作用 使开发者可以根据节点的关系获取元素, 而不是只能依赖选择器, 提高了编码的灵活性 节点分类 元素节点: 所有的标签都是元素节点, html是根节点属性节点: 所有的属性都是属性节点, 比如href文本节点: 所有的文…...
基于SpringBoot+Vue的论坛网站系统(带1w+文档)
基于SpringBootVue的论坛网站系统(带1w文档) 对于之前论坛网站的管理,大部分都是使用传统的人工方式去管理,这样导致了管理效率低下、出错频率高。而且,时间一长的话,积累下来的数据信息不容易保存,对于查询、更新还有…...
03逻辑门电路
分立门电路: 集成门电路: TTL门电路 MOS门电路:NMOS门电路、PMOS门电路、CMOS门电路 BICMOS门电路:CMOS的高输入阻抗和TTL的高放大倍数的结合 向更低功耗、更高速度发展 MOS管的Rdson在可变电阻区的阻值也一般会小于1000欧姆 …...
2毛钱的SOT23-5封装28V、1.5A、1.2MHz DCDC转换器用于LCD偏置电源和白光LED驱动等MT3540升压芯片
前言 之前发了一个TI的BOOST升压芯片,用于LCD偏置电压或LED驱动,请访问以下链接。 6毛钱SOT-23封装28V、400mA 开关升压转换器,LCD偏置电源和白光LED应用芯片TPS61040 国产半导体厂家发展迅猛,今天推荐一个公司带“航天”的升压…...
Zookeeper部署
Zookeeper部署 下载安装包Linux解压安装包修改配置文件编辑zoo.cf配置 启动服务停止服务常用zookeeper指令查看namespace列表创建namespace删除namespace 注意:该文章为简单部署操作,没有复杂的配置内容,用的是3.7.2版本。 下载安装包 进入z…...
2.x86游戏实战-跨进程读取血量
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 接下来会写C/C代码,C/C代码不是很难,然后为了快速掌握逆向这个技能,我…...
element-plus 日期选择添加确定按钮
需求:选择日期后,点击确定按钮关闭面板 思路: 使用shortcuts自定义确定和取消按钮选择日期后使用handleOpen()强制开启面板点击确定后使用handleClose()关闭面板 <template><el-date-pickerref"pickerRef"v-model"…...
Redis优化之持久化
目录 1.Redis高可用 2.Redis持久化 2.1 RDB持久化 2.1.1 触发条件 2.1.2 执行流程 2.1.3 启动时加载 2.2 AOF持久化 2.2.1 开启AOF 2.2.2 执行流程 2.2.3 文件重写触发方式 2.2.4 文件重写的流程 2.2.5 启动时加载 2.3 RDB和AOF的优缺点 3.Redis性能管理 3.1 查看…...
ubuntu22.04 编译安装libcurl C++ library
1. 安装必须的依赖项 sudo apt update #sudo apt install build-essential autoconf libtool pkg-config libssl-dev libz-dev 2. 下载及编译前准备 cd /opt mkdir curl && cd curl mkdir build && mkdir install git clone https://github.com/curl/curl.git…...
js函数闭包解析
闭包是JavaScript中非常重要的概念,理解闭包对于编写高质量的代码是至关重要的。本文将详细解析闭包的概念,并提供一些代码示例来帮助读者更好地理解闭包的使用。 什么是闭包? 闭包是指在一个函数内部定义的函数,该函数可以访问包…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
