ViewGroup是如何获取到xml中child设置的对应的属性的?

简介: ViewGroup是如何获取到xml中child设置的对应的属性的?

以常规的Activity启动开始,我们追一下详细的调用栈。

android sdk版本是30。

Activity#setContent方法中的布局如何生成View对象的:


--> ActivityThread#handleLaunchActivity

--> ActivityThread#performLaunchActivity

--> Instrumentation#callActivityOnCreate

--> Activity#performCreate(Bundle icicle)

--> Activity#performCreate(Bundle icicle, PersistableBundle persistentState)

--> Activity#onCreate(Bundle savedInstanceState)

--> AppCompatActivity#setContentView(@LayoutRes int layoutResID)

--> AppCompatDelegateImpl#setContentView(int resId)

------① AppCompatDelegateImpl#ensureSubDecor():初始化好DecorView。

------> PhoneWindow#getDecorView()

------> PhoneWindow#installDecor()

------> PhoneWindow#generateLayout(DecorView decor)

------> DecorView#onResourcesLoaded(LayoutInflater inflater, int layoutResource):返回一个View。

------> LayoutInflate#inflate(@LayoutRes int resource, @Nullable ViewGroup root)

----------先调用LayoutInflate#tryInflatePrecompiled方法,尝试获取View。默认mUseCompiledView为false,直接返回null。

----------上面方法获取不到时,接着获取XmlResourceParser,通过LayoutInflate#inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)方法获取View。

------② 调用LayoutInflater.from(mContext).inflate(resId, contentParent):将Activity#setContentView方法中设置的资源文件生成对应的View并添加到contentParent中。

LayoutInflater#inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)方法中:


①AttributeSet attrs = Xml.asAttributeSet(parser):从XmlPullParser中获取到AttributeSet

②通过advanceToRootNode(parser)方法,找到START_TAG后面的第一个元素;通过parser.getName()获取到name——"LinearLayout"

③通过LayoutInflater#createViewFromTag(View parent, String name, Context context, AttributeSet attrs)获取View

——> LayoutInflater#createViewFromTag(View parent, String name, Context context, AttributeSet attrs,boolean ignoreThemeAttr)

----调用LayoutInflater#tryCreateView方法:尝试创建View。本次返回null。

--------先使用mFactory2#onCreateView方法,调用到AppCompatViewInflater#createView方法中,这里做一些hook,将TextView、ImageView、Button、EditText、CheckBox等基础组件,替换成AppCompat系列组件。不过没有处理LinearLayout,所以返回view为null。

--------如果view为null,接着调用mPrivateFactory.onCreateView方法,这里会先调用FragmentActivity#dispatchFragmentsOnCreateView方法,看是否是"fragment"标签;如果不是,就调用Activity#onCreateView方法进行传递。这里也返回为null。

----如果tryCreateView创建View失败,则接着调用LayoutInflater#onCreateView(@NonNull Context viewContext, @Nullable View parent, @NonNull String name, @Nullable AttributeSet attrs)方法;

------>调用LayoutInflater#onCreateView(View parent, String name, AttributeSet attrs);

------>调用LayoutInflater#onCreateView(String name, AttributeSet attrs)方法;设置prefix为"android.view."。

------>调用LayoutInflater#createView(String name, String prefix, AttributeSet attrs)

------>调用LayoutInflater#createView(Context viewContext, String name, String prefix, AttributeSet attrs):

----------通过prefix和name获取Constructor对象。

----------构建Object[] args参数,依次传入上下文、attrs,然后通过反射生成LinearLayout的对象,调用的是LinearLayout(Context context, AttributeSet attrs)构造方法。

----------返回生成的View对象。

④如果root != null,就调用root.generateLayoutParams方法生成LayoutParams;如果attachToRoot为false,就将LayoutParams设置给③生成的View。

⑤调用LayoutInflater#rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs, boolean finishInflate):生成child对象

--> LayoutInflater#rInflate(XmlPullParser parser, View parent, Context context, AttributeSet attrs, boolean finishInflate)

---- 开启while循环:((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT

----------通过parser.getName()获取name,针对"requestFocus"、"tag"、"include"、"merge"和else情况做不同的处理。

----------else情况下:

--------------通过LayoutInflater#createViewFromTag(View parent, String name, Context context, AttributeSet attrs)获取View。

--------------通过parent#generateLayoutParams方法,从xml中读取parent对应的数据,生成对应的LayoutParams数据,包括基础的layout_width和layout_height,一个给个ViewGroup自定义的LayoutParams数据。

--------------递归调用LayoutInflater#rInflateChildren,对View的child创建。

--------------通过ViewGroup#addView(View child, LayoutParams params)方法,将child添加进parent。

⑥如果root != null && attachToRoot,通过ViewGroup#addView(View child, LayoutParams params)方法,将child和④生成的LayoutParams数据,添加进root。

⑦如果root == null || !attachToRoot,将temp赋值给result。

结论:

在从xml文件变成View对象,并添加到View树的过程中,必然会调用parent#generateLayoutParams方法。

ViewGroup#generateLayoutParams方法中,会读取layout_widthlayout_height基础属性。

由于各个控件都是继承自ViewGroup的,他们一般会继承ViewGroup.LayoutParams,并据此重写自己的generateLayoutParams方法,在generateLayoutParams方法中一般都会从child的属性中读取自己关注的属性,所以此时写在child中的xml属性会被读取,从而生效。

相关文章
|
8月前
|
XML 存储 JSON
使用自定义XML配置文件在.NET桌面程序中保存设置
本文将详细介绍如何在.NET桌面程序中使用自定义的XML配置文件来保存和读取设置。除了XML之外,我们还将探讨其他常见的配置文件格式,如JSON、INI和YAML,以及它们的优缺点和相关的NuGet类库。最后,我们将重点介绍我们为何选择XML作为配置文件格式,并展示一个实用的示例。
99 0
|
6天前
|
XML JavaScript 前端开发
XML DOM - 属性和方法
XML DOM通过属性(如nodeName、nodeValue、parentNode、childNodes和attributes)和方法提供编程接口,让开发者用JavaScript等语言以节点方式交互XML。属性描述节点信息,方法执行操作,如删除节点。
|
6天前
|
XML JavaScript 前端开发
XML DOM - 属性和方法
XML DOM 提供编程接口,让开发者用JavaScript等语言操作XML文档。接口包含属性和方法,属性如nodeName、nodeValue、parentNode和childNodes,用于查询节点信息;方法如getElementsByTagName、appendChild和removeChild,执行增删操作。示例中,JavaScript代码`txt=xmlDoc.getElementsByTagName("title")[0].childNodes[0].nodeValue`从books.xml获取第一个<title>元素的文本内容,赋值给变量txt。
|
6天前
|
XML JavaScript 数据格式
python - bs4提取XML/HTML中某个标签下的属性
python - bs4提取XML/HTML中某个标签下的属性
30 0
|
7月前
|
JavaScript 前端开发 安全
12dwr - dwr.xml配置(allow标签-Converter属性)
12dwr - dwr.xml配置(allow标签-Converter属性)
24 0
|
7月前
|
开发框架 JavaScript 前端开发
11dwr - dwr.xml配置(allow标签-Creator属性)
11dwr - dwr.xml配置(allow标签-Creator属性)
28 0
|
7月前
|
XML 数据管理 数据处理
XML入门,之dtd属性与元素详解
XML入门,之dtd属性与元素详解
28 1
|
10月前
|
XML 设计模式 Java
Spring——Bean管理-xml方式进行属性注入
目前的问题:只能当前类使用,其他类不能用,接下来就是把集合属性抽取成公共部分让所有实体类都能够引入
|
XML Java 开发工具
Android常见XML属性解析
Android常见XML属性解析
177 0
|
XML Linux 数据格式
全网首发:多个mimetypes xml设置某种文件类型的不同图标,LINUX怎样确定使用哪个
全网首发:多个mimetypes xml设置某种文件类型的不同图标,LINUX怎样确定使用哪个
113 0