布局文件是如何被解析的?
原理
通过layoutId,装换成xml对象,XmlResourceParser,将XmlResourceParser转成AttributeSet对象,根据XmlResourceParser的name得到view对象的类型,最后根据Constructor实例化view对象
几个概念
XmlResourceParser
- 将xml转换成java对象,就是XmlResourceParser
- Rescources class 中,根据resourceid,获得XmlResourceParser对象
@NonNullXmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)throws NotFoundException {final TypedValue value = obtainTempTypedValue();try {final ResourcesImpl impl = mResourcesImpl;impl.getValue(id, value, true);if (value.type == TypedValue.TYPE_STRING) {return impl.loadXmlResourceParser(value.string.toString(), id,value.assetCookie, type);}throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)+ " type #0x" + Integer.toHexString(value.type) + " is not valid");} finally {releaseTempTypedValue(value);}}
AttributeSet
- xml中标签对应的java对象,如layout_width等
- 利用Xml class中的方法,生成AttributeSet对象
public static AttributeSet asAttributeSet(XmlPullParser parser) {return (parser instanceof AttributeSet)? (AttributeSet) parser: new XmlPullAttributes(parser);}
Constructor
- 属于反射的一种方式,通过constructor可以获取某个具体的类。 提供有关类的单个构造函数的访问和访问的信息。
- 在xml解析成XmlPullParser时,将XmlPullParser解析成AttributeSet,获取AttributeSet的name,Constructor根据有包名的name,实例化一个view。
final View view = constructor.newInstance(args);
源码
layoutInflater
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {final Resources res = getContext().getResources();if (DEBUG) {Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("+ Integer.toHexString(resource) + ")");}final XmlResourceParser parser = res.getLayout(resource);//画重点try {return inflate(parser, root, attachToRoot);} finally {parser.close();}}
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,boolean ignoreThemeAttr) {if (name.equals("view")) {name = attrs.getAttributeValue(null, "class");}// Apply a theme wrapper, if allowed and one is specified.if (!ignoreThemeAttr) {final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);final int themeResId = ta.getResourceId(0, 0);if (themeResId != 0) {context = new ContextThemeWrapper(context, themeResId);}ta.recycle();}if (name.equals(TAG_1995)) {// Let's party like it's 1995!return new BlinkLayout(context, attrs);}try {View view;//重点,通过设置Factory,可以达到将系统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);}if (view == null) {final Object lastContext = mConstructorArgs[0];mConstructorArgs[0] = context;try {//重点,如果是系统控件,则会在name前面加上"android.view."if (-1 == name.indexOf('.')) {view = onCreateView(parent, name, attrs);} else {view = createView(name, null, attrs);}} finally {mConstructorArgs[0] = lastContext;}}return view;}...}
public final View createView(String name, String prefix, AttributeSet attrs)throws ClassNotFoundException, InflateException {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 itclazz = mContext.getClassLoader().loadClass(prefix != null ? (prefix + name) : name).asSubclass(View.class);if (mFilter != null && clazz != null) {boolean allowed = mFilter.onLoadClass(clazz);if (!allowed) {failNotAllowed(name, prefix, 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 = mContext.getClassLoader().loadClass(prefix != null ? (prefix + name) : name).asSubclass(View.class);//重点,如果是boolean allowed = clazz != null && mFilter.onLoadClass(clazz);mFilterMap.put(name, allowed);if (!allowed) {failNotAllowed(name, prefix, attrs);}} else if (allowedState.equals(Boolean.FALSE)) {failNotAllowed(name, prefix, attrs);}}}Object[] args = mConstructorArgs;args[1] = attrs;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;} ...}
Resources
public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {return loadXmlResourceParser(id, "layout");}
@NonNullXmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)throws NotFoundException {final TypedValue value = obtainTempTypedValue();try {final ResourcesImpl impl = mResourcesImpl;impl.getValue(id, value, true);if (value.type == TypedValue.TYPE_STRING) {return impl.loadXmlResourceParser(value.string.toString(), id,value.assetCookie, type);//重点}throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)+ " type #0x" + Integer.toHexString(value.type) + " is not valid");} finally {releaseTempTypedValue(value);}}
转载于:https://www.cnblogs.com/qinhe/p/6370781.html
布局文件是如何被解析的?相关推荐
- Android布局文件的布局方式
Android布局文件的属性值解析说明: 1.android:id [为控件指定相应的ID] 2.android:text [指定控件当中显示的文字,需要注意的是,这里尽量使用strings.xm ...
- Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析
转自:http://www.uml.org.cn/mobiledev/201211221.asp 今天,我着重讲解下如下三个内容: measure过程 WRAP_CONTENT.MATCH_PAREN ...
- Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)
本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...
- Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)
在之前一篇博文中<< Android中View绘制流程以及invalidate()等相关方法分析>> ,简单的阐述 了 Android View 绘制流程的三个步骤,即: 1. ...
- 【Android】安卓布局文件中xmlns属性
定义及使用 xmlns是XML Namespaces的缩写,中文名称是XML(标准通用标记语言的子集)命名空间 自定义View的时候有时候会在布局文件中使用到 命名规则如下: xmlns:前缀=htt ...
- 实例化Layout中的布局文件(xml)
什么是LayoutInflater This class is used to instantiate layout XML file into its corresponding View obje ...
- android 刷卡布局,刷卡布局效果-开源AndroidSwipeLayout使用解析(二)
上一篇解析了AndroidSwipeLayout的普通用法 这一次我们来看一下它在ListView中的使用,同样我们分析官方的sample来学习如何使用 在上一篇忘了给出它的gradle配置 同样看分 ...
- Android 开发之旅:深入分析布局文件又是“Hello World!”
引言 上篇可以说是一个分水岭,它标志着我们从Android应用程序理论进入实践,我们拿起手术刀对默认的"Hello World!"程序进行了3个手术,我们清楚了"Hell ...
- java编写布局文件_鸿蒙OS利用JAVA编写的布局实践练习
鸿蒙OS利用JAVA编写的布局实践练习 鸿蒙OS利用JAVA编写的布局实践练习 目录 JAVA UI框架 利用JAVA代码实现一个简单的布局 利用xml实现上述布局 JAVA UI框架 ??应用的Ab ...
- 2.2 LayoutInflater 加载布局文件源码
LayoutInflater 加载布局文件源码 LayoutInflater是一个用于将xml布局文件加载为View或者ViewGroup对象的工具,我们可以称之为布局加载器. 获取LayoutInf ...
最新文章
- Android 获取SD卡的图片资源
- mysql闪退或者can not connect 127.0.0.1
- 互联网趋势关键词:交流,为价值付费,资源整合
- php json 转 xml格式,PHP中如何将JSON文件转XML格式
- 农行计算机安全制度,制度体系之农行 数据中心计算机安全检查实施细则.doc
- ★ Learn how you can use Adobe Creative Suite to create skins for Flex and AIR applications.
- jsp中嵌入java代码实例,jsp中嵌入java代码
- torch.randn 方法
- 银行卡支付之连连支付
- 这套表情包,居然开源了!!
- DNS是如何进行域名解析的?
- 经典的搞笑图片集,让你轻松一下
- 小程序根据地址信息获取经纬度导航功能实现
- 数据库包含哪几种锁?
- 海思Hi3559(十)——生成wk数据文件
- python自动添加cad点坐标_利用pyautocad模块批量画点位
- 基于51单片机的室内温度可燃气体检测报警系统Proteus仿真(源码+仿真+全套资料)
- bat批量提取word文件名
- Silverlight5 做的打印用针式打印机打印时,为什么非常不清楚?
- 什么软件可以搜python题_哪个手机软件有python题库
热门文章
- 平衡——职场小说《监控》推荐
- caffe的python接口学习:caffemodel中的参数及特征的抽取(转载)
- 小瓦怕扫地机器人_小瓦扫地机器人青春版评测:便宜有好货
- relu函数_激活函数解析:Sigmoid, tanh, Softmax, ReLU, Leaky ReLU
- python代码写不出来怎么办_为什么python这个代码写出来的图片不显示?
- html幻灯片效果需要js吗,js 幻灯片的实现
- L1-047 装睡 (10 分)—团体程序设计天梯赛
- L1-046 整除光棍 (20 分)—团体程序设计天梯赛
- rk3399_secureboot在linux环境中操作说明
- 《TCP/IP 详解 卷1:协议》第 2 章:Internet 地址结构