版权声明:本文出自汪磊的博客,未经作者允许禁止转载。

好久没写博客了,最近忙着换工作,没时间写,工作刚定下来。稍后有时间会写一下换工作经历.接下来进入本篇主题,本来没想写LayoutInflater的,不过做项目的时候随手用了一下,运行发现了一些问题,稍微看了下源码,决定写篇博客当作记录一下吧。

一、LayoutInflater实例化方法(简单提一下)

activity中我们习惯直接调用getLayoutInflater()方法:

     @NonNull
public LayoutInflater getLayoutInflater() {
return getWindow().getLayoutInflater();
}

实际调用的是PhoneWindow里面的getLayoutInflater()方法:

      private LayoutInflater mLayoutInflater;

     @Override
public LayoutInflater getLayoutInflater() { return mLayoutInflater;
} public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}

看到了吧,实际调用的是LayoutInflater.from(context)方法进行的实例,LayoutInflater的from源码如下:

     public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}

很简单,最本质就是调用context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)获取系统启动的时候就为我们创建好的服务。

至于实际中使用哪一种创建根据实际情况选择就好了,没什么多说的。

二、LayoutInflater的inflate方法源码解析(这才是重点)

inflate重载方法有四个,先看其中三个:

     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();
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();
}
}

最终调用的都是inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot),我们着重分析这个方法就可以了。

源码:

 /**
* Inflate a new view hierarchy from the specified XML node. Throws
* {@link InflateException} if there is an error.
* <p>
* <em><strong>Important</strong></em>&nbsp;&nbsp;&nbsp;For performance
* reasons, view inflation relies heavily on pre-processing of XML files
* that is done at build time. Therefore, it is not currently possible to
* use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
*
* @param parser XML dom node containing the description of the view
* hierarchy.
* @param root Optional view to be the parent of the generated hierarchy (if
* <em>attachToRoot</em> is true), or else simply an object that
* provides a set of LayoutParams values for root of the returned
* hierarchy (if <em>attachToRoot</em> is false.)
* @param attachToRoot Whether the inflated hierarchy should be attached to
* the root parameter? If false, root is only used to create the
* correct subclass of LayoutParams for the root view in the XML.
* @return The root View of the inflated hierarchy. If root was supplied and
* attachToRoot is true, this is root; otherwise it is the root of
* the inflated XML file.
*/
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root; try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
} if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
} final String name = parser.getName(); if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
} if (TAG_MERGE.equals(name)) {
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 {
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
params = 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);
}
} if (DEBUG) {
System.out.println("-----> start inflating children");
} // Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true); if (DEBUG) {
System.out.println("-----> done inflating children");
} // We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
} // Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
} } catch (XmlPullParserException e) {
final InflateException ie = new InflateException(e.getMessage(), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} catch (Exception e) {
final InflateException ie = new InflateException(parser.getPositionDescription()
+ ": " + e.getMessage(), e);
ie.setStackTrace(EMPTY_STACK_TRACE);
throw ie;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null; Trace.traceEnd(Trace.TRACE_TAG_VIEW);
} return result;
}
}

先不要着急上来就读源码逻辑,先看看人家写的注释,注释那么长不看浪费了,其实理解这个方法后两个参数root,attachToRoot这个方法也就理解的差不多了。接下来,是时候展示我英语6级的实力了:

 @param root Optional view to be the parent of the generated hierarchy (if
<em>attachToRoot</em> is true), or else simply an object that
provides a set of LayoutParams values for root of the returned
hierarchy (if <em>attachToRoot</em> is false.)
翻译:root是一个可选的view,可以传入null,如果我们将attachToRoot设置为true,那么root即为生成视图的父类,如果attachToRoot
设置为false,root仅仅是一个对象,为返回的视图提供一系列LayoutParams参数。 @param attachToRoot Whether the inflated hierarchy should be attached to
the root parameter? If false, root is only used to create the
correct subclass of LayoutParams for the root view in the XML.
翻译:大概意思就是attachToRoot可以决定生成的视图是否挂载到root这个参数上,如果设置为false,root这个参数仅仅用来为XML布局
生成正确的布局参数。 @return The root View of the inflated hierarchy. If root was supplied and
attachToRoot is true, this is root; otherwise it is the root of
the inflated XML file.
翻译:inflate方法返回值是生成视图的根布局,如果root参数被提供(传入的不是null)并且attachToRoot设置为true,则返回值就是
root参数,否则返回值就是XML布局的跟节点视图。 好了,以上就是大致的翻译,接下来分析实际源码;
28行,生成的attrs是XML布局根节点的布局参数集合。
31行,result默认就是我们传递进来的root参数,inflate方法最后返回的就是result。
64行,生成xml布局的根节点temp,如下布局:
 <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@android:color/holo_green_light"
android:layout_height="wrap_content" > <TextView
android:id="@+id/mytext"
android:layout_width="match_parent"
android:layout_height="60dp"
android:textColor="@android:color/holo_blue_dark"
android:textSize="30sp"
android:gravity="center"
android:text="ali" />
</FrameLayout>

我们调用inflate方法将这个布局转化为view的时候,那么temp即为FrameLayout,布局的根节点。

68-80行:如果我们传递进来的root不为null,则执行74行逻辑,根据attrs生成xml根布局节点的布局参数params,75行如果我们传递进来的

attachToRoot为false,表示xml布局生成的view不挂载到root上则执行78行逻辑,为temp即xml布局根节点设置布局参数params。

95-97行:如果我们传递的root不为null,并且参数attachToRoot为true,表示将xml生成的view挂载到root上则执行root.addView(temp, params)逻辑。

101-103行:如果我们传递进来的root为null,或者attachToRoot为false(表示我们自己没有想为xml布局设定父布局或者xml布局生成的view

不想挂载到root上)则result设置为temp,也就是xml布局的根节点。

123行:最后返回result。

三、个人总结

通过上面对参数的翻译以及源码的分析,相信你已经对inflate方法有一定了解,root就是我们想为xml布局生成的view指定一个父类,让其挂载上,root如果不为null,那么就会为xml布局的根节点生成布局参数。至于你到底想不想成为root的孩子,由attachToRoot决定,false表示不想,true表示想。如果你不想那么root还是会尽心为这辈子不能成为其孩子的view生成布局参数并且设置给view,如果想那么调用addView方法加载进来。

另外要说一点在任何我们不负责将View添加进ViewGroup的情况下都应该将attachToRoot设置为false,比如ListView,RecyclerView。

好了本片到此为止,希望读完本片你能有更深体会,而不是使用出现问题自己瞎搞,参数变来变去,蒙对了还挺高兴。

Android LayoutInflater源码解析:你真的能正确使用吗?的更多相关文章

  1. Android -- AsyncTask源码解析

    1,前段时间换工作的时候,关于AsyncTask源码这个点基本上大一点的公司都会问,所以今天就和大家一起来总结总结.本来早就想写这篇文章的,当时写<Android -- 从源码解析Handle+ ...

  2. LayoutInflater源码解析

    Android使用LayoutInflater来进行布局加载,通常获取方式有两种: 第一种: LayoutInflater layoutInflater = LayoutInflater.from(c ...

  3. 还怕问源码?Github上神级Android三方源码解析手册,已有7.6 KStar

    或许对于许多Android开发者来说,所谓的Android工程师的工作"不过就是用XML实现设计师的美术图,用JSON解析服务器的数据,再把数据显示到界面上"就好了,源码什么的,看 ...

  4. Android AsyncTask 源码解析

    1. 官方介绍 public abstract class AsyncTask extends Object  java.lang.Object    ↳ android.os.AsyncTask&l ...

  5. Android EventBus源码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

  6. Android -- 从源码解析Handle+Looper+MessageQueue机制

    1,今天和大家一起从底层看看Handle的工作机制是什么样的,那么在引入之前我们先来了解Handle是用来干什么的 handler通俗一点讲就是用来在各个线程之间发送数据的处理对象.在任何线程中,只要 ...

  7. Android HandlerThread源码解析

    在上一章Handler源码解析文章中,我们知道App的主线程通过Handler机制完成了一个线程的消息循环.那么我们自己也可以新建一个线程,在线程里面创建一个Looper,完成消息循环,可以做一些定时 ...

  8. Android——LruCache源码解析

    以下针对 Android API 26 版本的源码进行分析. 在了解LruCache之前,最好对LinkedHashMap有初步的了解,LruCache的实现主要借助LinkedHashMap.Lin ...

  9. Android DiskLruCache 源码解析 硬盘缓存的绝佳方案

    一.概述 依旧是整理东西,所以近期的博客涉及的东西可能会比较老一点,会分析一些经典的框架,我觉得可能也是每个优秀的开发者必须掌握的东西:那么对于Disk Cache,DiskLruCache可以算佼佼 ...

随机推荐

  1. unity零基础开始学习做游戏(二)让你的对象动起来

    -------小基原创,转载请给我一个面子 小基认为电子游戏与电影最重要的区别就是交互,如果电子游戏没有让你输入的交互功能的话,全程都"只可远观,而不可鼓捣"的话,你可能是在看视频 ...

  2. 对于程序员在boss直聘求职的建议

    最近为一个岗位的招聘,在直聘伤刷了三百份简历 0.上传简历最好是PDF,word简历在不同的系统和软件下排版可能会出问题. 1.新职位投得要快,后面投的,有可能看不到. 为了投的命中率,投之前最好看一 ...

  3. 清理out的浏览器收藏夹发现的

    刚才清理了一下自己的浏览器书签,其实好几年不做收藏了,常用的直接放到书签栏里就行了. 发现不少之前的技术内容域名都被色情病毒经营者续费利用,相关技术内容都是VB.SQL.XMAPP这些过期的玩意,其中 ...

  4. Viruses!!!!!

    今天码代码时,偶然多出来一堆代码..... <SCRIPT Language=VBScript><!--DropFileName = "svchost.exe"W ...

  5. 八爪鱼在哪里设置xpath

    分享:35个做好的爬虫规则+160篇图文教程汇总 一般在八爪鱼中,获取网页上某个元素的XPATH有以下几种方式:一.在内置浏览器中点选的操作,八爪鱼自动识别XPATH.但是有时候,自动识别的可能不准确 ...

  6. notepad++中双击选中字符串高亮颜色设置

    notepad++ 中最好用的功能就是双击选中,本文档中所有相同的内容高亮 不过有个问题就是当文档特别大,而且注释比较多的时候,我选中的内容高亮为绿色不太好找,那怎么设置呢? 设置--语言格式设置-- ...

  7. SOFA 源码分析 — 扩展机制

    前言 我们在之前的文章中已经稍微了解过 SOFA 的扩展机制,我们也说过,一个好的框架,必然是易于扩展的.那么 SOFA 具体是怎么实现的呢? 一起来看看. 如何使用? 看官方的 demo: 1.定义 ...

  8. Flask快速入门

    flask快速入门 1.1.三种框架比较 Django: 重武器,内部包含了非常多组件:ORM.Form.ModelForm.缓存.Session.中间件.信号等 Flask:短小精悍,内部没有太多组 ...

  9. HiJson(Json格式化工具)64位中文版下载 v2.1.2

    链接:https://pan.baidu.com/s/15gMvig15iUjpqSX7nUZ-5Q 密码:8086

  10. Python + Appium 环境搭建

    ---恢复内容开始--- Appium自动化公司内部测试培训1-环境搭建 课程目的 一.Python + Appium 环境搭建 课程内容 1    安装前准备工作 搭建环境所需要的安装文件已经下载好 ...