type
status
date
slug
summary
tags
category
icon
password
两种资源
- 预编译的layout资源(dex文件)
- xml layout文件
预编译的布局
目前的版本(Android 11)并没有开放这个功能.
基本的处理流程如下:
- 使用view_compiler将xml布局直接编译成CompiledView.java文件;
源码地址: view_compiler
整个app的预编译layout资源最后会打包到compiled_view.dex文件中;
- 在需要渲染xml布局的地方使用
CompiledView.infalte
替代
xml布局
看了上面这部分的代码,逻辑算是比较清晰的了:
- 获取Resources对象,通过Resources对象获取到与resourceId绑定的XmlResourceParser对象;
- 使用XmlResourceParser解析XML Layout结构;
- 先获取到根节点(即第一个START TAG),然后进行递归遍历,先搞定内部嵌套的的结构,再搞定外部的结构;
- 从XML Tag创建View的过程中间可以通过Factory/Factory2等进行代理/拦截,如果不做处理,则会使用反射进行创建;
从XML TAG 到 View
如果不设置各种Factory,则最终会调用LayoutInflater的
createView()
方法,从XML tag通过反射创建View对象;主要步骤如下:
- 找到或者创建对应的Constructor;
- 进行Filter拦截处理,判断是否允许对应的View被加载成类;
- 使用Constructor通过反射创建View对象;
- 如果创建的View对象是ViewStub,则将当前的LayoutInflater设置给它;
其实分析到这里还有几个关键问题没有提及到:
- XmlResourceParser是如何创建的?作为一个XmlPullParser的实现,又是在哪设置的输入,将xml文件输入到API中的?
- Android Layout文件中View的各种属性是如何与对应View进行绑定的,或者说是暂时存储在哪的?
XmlResourceParser的创建
在Resources中有:
在ResourcesImpl中有:
这里再看看XMLBlock的创建:
XMLBlock中有:
frameworks/base/core/jni/android_util_AssetManager.cpp
中有:到这里可以看到流程如下:
- C++层通过assetmanager根据resId + DynamicRefTable获取到对应资源文件的buffer和大小,并将数据设置到ResXmlTree中,并返回其地址,作为Java层的XmlBlock;
- Java层中XmlResourcesParser的解析工作其实是通过XmlBlock中的内部类Parser去完成的,而XmlBlock层中有来自于C++层的ResXmlTree的地址,因此刚刚好可以用来读取布局数据;
XmlBlock中的解析
看下next()方法实现就差不多了,其他很多方法都在C++层,这里只需要知道XmlResourcesParser的实现类其实是XmlBlock中的Parser即可;
Layout文件中属性的绑定
其实前面在解析的时候有下面这一句:
因为XmlResourcesParser本身就是实现的AttributeSet,因此可以进行转换;
然后这个AttributeSet会在加载渲染的过程中传递给View.主要有两个用途:
- 设置布局的layout_width/layout_height
- 在反射创建View的时候作为参数传入
可以看到反射一定会调用到
View(Context,AttributeSet)
;这个时候会传入Context参数和AttributeSet参数.便于View去处理各种属性.- 作者:姜康
- 链接:https://jiangkang.tech/article/64ec557c-e702-4d38-a261-08a0957925ff
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。