原理

通过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

布局文件是如何被解析的?相关推荐

  1. Android布局文件的布局方式

    Android布局文件的属性值解析说明:   1.android:id [为控件指定相应的ID] 2.android:text [指定控件当中显示的文字,需要注意的是,这里尽量使用strings.xm ...

  2. Android中measure过程、WRAP_CONTENT详解以及 xml布局文件解析流程浅析

    转自:http://www.uml.org.cn/mobiledev/201211221.asp 今天,我着重讲解下如下三个内容: measure过程 WRAP_CONTENT.MATCH_PAREN ...

  3. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)

       本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...

  4. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)

    在之前一篇博文中<< Android中View绘制流程以及invalidate()等相关方法分析>> ,简单的阐述 了 Android View 绘制流程的三个步骤,即: 1. ...

  5. 【Android】安卓布局文件中xmlns属性

    定义及使用 xmlns是XML Namespaces的缩写,中文名称是XML(标准通用标记语言的子集)命名空间 自定义View的时候有时候会在布局文件中使用到 命名规则如下: xmlns:前缀=htt ...

  6. 实例化Layout中的布局文件(xml)

    什么是LayoutInflater This class is used to instantiate layout XML file into its corresponding View obje ...

  7. android 刷卡布局,刷卡布局效果-开源AndroidSwipeLayout使用解析(二)

    上一篇解析了AndroidSwipeLayout的普通用法 这一次我们来看一下它在ListView中的使用,同样我们分析官方的sample来学习如何使用 在上一篇忘了给出它的gradle配置 同样看分 ...

  8. Android 开发之旅:深入分析布局文件又是“Hello World!”

    引言 上篇可以说是一个分水岭,它标志着我们从Android应用程序理论进入实践,我们拿起手术刀对默认的"Hello World!"程序进行了3个手术,我们清楚了"Hell ...

  9. java编写布局文件_鸿蒙OS利用JAVA编写的布局实践练习

    鸿蒙OS利用JAVA编写的布局实践练习 鸿蒙OS利用JAVA编写的布局实践练习 目录 JAVA UI框架 利用JAVA代码实现一个简单的布局 利用xml实现上述布局 JAVA UI框架 ??应用的Ab ...

  10. 2.2 LayoutInflater 加载布局文件源码

    LayoutInflater 加载布局文件源码 LayoutInflater是一个用于将xml布局文件加载为View或者ViewGroup对象的工具,我们可以称之为布局加载器. 获取LayoutInf ...

最新文章

  1. Android 获取SD卡的图片资源
  2. mysql闪退或者can not connect 127.0.0.1
  3. 互联网趋势关键词:交流,为价值付费,资源整合
  4. php json 转 xml格式,PHP中如何将JSON文件转XML格式
  5. 农行计算机安全制度,制度体系之农行 数据中心计算机安全检查实施细则.doc
  6. ★ Learn how you can use Adobe Creative Suite to create skins for Flex and AIR applications.
  7. jsp中嵌入java代码实例,jsp中嵌入java代码
  8. torch.randn 方法
  9. 银行卡支付之连连支付
  10. 这套表情包,居然开源了!!
  11. DNS是如何进行域名解析的?
  12. 经典的搞笑图片集,让你轻松一下
  13. 小程序根据地址信息获取经纬度导航功能实现
  14. 数据库包含哪几种锁?
  15. 海思Hi3559(十)——生成wk数据文件
  16. python自动添加cad点坐标_利用pyautocad模块批量画点位
  17. 基于51单片机的室内温度可燃气体检测报警系统Proteus仿真(源码+仿真+全套资料)
  18. bat批量提取word文件名
  19. Silverlight5 做的打印用针式打印机打印时,为什么非常不清楚?
  20. 什么软件可以搜python题_哪个手机软件有python题库

热门文章

  1. 平衡——职场小说《监控》推荐
  2. caffe的python接口学习:caffemodel中的参数及特征的抽取(转载)
  3. 小瓦怕扫地机器人_小瓦扫地机器人青春版评测:便宜有好货
  4. relu函数_激活函数解析:Sigmoid, tanh, Softmax, ReLU, Leaky ReLU
  5. python代码写不出来怎么办_为什么python这个代码写出来的图片不显示?
  6. html幻灯片效果需要js吗,js 幻灯片的实现
  7. L1-047 装睡 (10 分)—团体程序设计天梯赛
  8. L1-046 整除光棍 (20 分)—团体程序设计天梯赛
  9. rk3399_secureboot在linux环境中操作说明
  10. 《TCP/IP 详解 卷1:协议》第 2 章:Internet 地址结构