为什么要看这个类的源码呢 ?是因为在使用RecyclerView时,对Item进行getLayoutParams操作时,报了空指针异常。通过对源码的分析,才知道问题是出在了是否正确的使用了LayoutInflater。这是一个比较冷门的问题,也是一个比较容易被忽略的问题。但是我们每次将布局转化成View时,都会使用到这个类,所以想要好好分析一下,顺便记录下来,加深自己的理解和记忆,同时也希望可以帮助到其他的人。

首先我们来看一下出问题的代码:


看源码,首先从最常用的方法开始看,其实也可以说,就看常用的方法就够了。所以我们要从inflate()的源码开始看起。
// TODO 补充:源代码的位置
在LayoutInflater.java中,一共有4个重载的inflate(),我们一个一个慢慢的看。

// 第一个
/*** Inflate a new view hierarchy from the specified xml resource. Throws* {@link InflateException} if there is an error.** @param resource ID for an XML layout resource to load (e.g.,*        <code>R.layout.main_page</code>)* @param root Optional view to be the parent of the generated hierarchy.* @return The root View of the inflated hierarchy. If root was supplied,*         this is the root View; otherwise it is the root of the inflated*         XML file.*/public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {return inflate(resource, root, root != null);}// 第二个/*** 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.* @return The root View of the inflated hierarchy. If root was supplied,*         this is the root View; otherwise it is the root of the inflated*         XML file.*/public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {return inflate(parser, root, root != null);}

可以看到,第一个inflate(resource,root)是两个参数的inflate,它实际上是调用了三个参数的inflate(int resource, ViewGroup root, boolean attachToRoot)。第二个inflate(parser,root)的第一个参数是XmlPullParser,它调用的是三个参数的inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)。开始分析第三个inflate

//第三个/*** Inflate a new view hierarchy from the specified xml resource. Throws* {@link InflateException} if there is an error.** @param resource ID for an XML layout resource to load (e.g.,*        <code>R.layout.main_page</code>)* @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(@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) + ")");}// 把resource转化为parser final XmlResourceParser parser = res.getLayout(resource);try {return inflate(parser, root, attachToRoot);} finally {parser.close();}}

查看源码发现,这个方法调用了三个参数的inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)。现在来重点分析这个方法:

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 xmlfinal 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 suppliedparams = 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;}}

在从上往下查看源码的过程中,我们看到了这样一句话:
params = root.generateLayoutParams(attrs);咦,我们的问题就是出在params上,params报空,因此我们往上看,看到了这一句: if (root != null) 原来问题出在了root上,查看我们出问题的代码,(写出出问题的代码)
再往下看:

 if (!attachToRoot) {// Set the layout params for temp if we are not// attaching. (If we are, we use addView, below)temp.setLayoutParams(params);}

也就是说,只有attachToRoot = false 时,才会将params设置到temp上去。

LayoutInflater源码分析相关推荐

  1. 【Android 插件化】VirtualApp 源码分析 ( 启动应用源码分析 | HomePresenterImpl 启动应用方法 | VirtualCore 启动插件应用最终方法 )

    文章目录 一.启动应用源码分析 1.HomeActivity 启动应用点击方法 2.HomePresenterImpl 启动应用方法 3.VirtualCore 启动插件应用最终方法 一.启动应用源码 ...

  2. 【Android 启动过程】Activity 启动源码分析 ( Activity -> AMS、主线程阶段 )

    文章目录 一.Activity 启动源码分析 ( Activity -> AMS 阶段 ) 一.Activity 启动源码分析 ( Activity -> AMS 阶段 ) 调用 star ...

  3. DialogFragment源码分析

    2019独角兽企业重金招聘Python工程师标准>>> 目录介绍 1.最简单的使用方法 1.1 官方建议 1.2 最简单的使用方法 1.3 DialogFragment做屏幕适配 2 ...

  4. android字符显示流程图,Android应用层View绘制流程与源码分析

    1  背景 还记得前面<Android应用setContentView与LayoutInflater加载解析机制源码分析>这篇文章吗?我们有分析到Activity中界面加载显示的基本流程原 ...

  5. Dialog源码分析

    目录介绍 1.简单用法 2.AlertDialog源码分析 2.1 AlertDialog.Builder的构造方法 2.2 通过AlertDialog.Builder对象设置属性 2.3 build ...

  6. 源码分析 merge 标签减少布局层级的秘密(Android Q)

    源码分析 merge 标签减少布局层级的秘密(Android Q) 我在<Android 渲染性能优化--你需要知道的一切!>一文中介绍过,merge 标签用于减少 View 树的层次来优 ...

  7. Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析

    1  背景 之所以写这一篇博客的原因是因为之前有写过一篇<Android应用setContentView与LayoutInflater加载解析机制源码分析>, 然后有人在文章下面评论和微博 ...

  8. leakcanary1.5源码分析

    文章目录 介绍 使用 问题 源码分析 总结 介绍 内存泄漏检测工具,square公司出品,github地址https://github.com/square/leakcanary. gradle引用: ...

  9. Android 12 新APP启动画面(SplashScreen API)简介源码分析

    以往的启动画面 默认情况下刚启动APP时会显示一会白色背景 如果把这个启动背景设置为null,则一闪而过的白色会变成黑色 如果把启动Activity设置为背景透明[< item name=&qu ...

最新文章

  1. java poi 导出 国际化_更好用的excel国际化多语言导出
  2. python语音翻译-python利用有道翻译实现“语言翻译器”的功能
  3. SAP Spartacus 服务器端渲染找不到 index 视图的问题
  4. angluar cdk_零分钟即可在容器开发套件(CDK)上实现云运营
  5. webpaper网页出题语言
  6. xlsx文件和csv文件的相互转化
  7. 吴恩达发布了大型X光数据集,斯坦福AI诊断部分超越人类 | AAAI 2019
  8. stl之set集合容器应用基础
  9. Photoshop 入门教程「6」如何更改图像大小?
  10. layui分页完整实例php,使用 layui 后端分页的实例
  11. 典型相关分析(cca)原理_全网最细的图文详解——手把手教你不会代码一样做RDA/CCA分析!...
  12. c语言easyx背景图片,C++之设置背景图片(Easyx)
  13. 【产品速递】云和恩墨ZDBM数据库备份一体机
  14. redis分布式代理工具选型与功能验证
  15. python qq群自动加入_Python实现向QQ群成员自动发邮件的方法
  16. es6 去掉空格_ES6之字符串
  17. 【Android驱动】aw9106驱动代码流程
  18. 天下国家之事,败于小人者十一,败于君子者十九(转)
  19. JAVA键盘录入 分支结构if swtich语句+循环结构for while语句 练习
  20. Android中复制到剪切板

热门文章

  1. list-style:none是什么意思
  2. “新元宇宙”奇科幻小说原创作品每周连载《地球人奇游天球记》第五回太空之旅
  3. 程序员,你是选择25k的996 还是18k的八小时?
  4. 启明云端分享:IDO-EVB6Y09 4G 工业路由器、4GDTU 和工业 HMI 三大功能于一体
  5. 软工网络16个人作业1
  6. CentOS网络设置
  7. 在线提问回答系统(类似知乎)毕业设计
  8. 基于CubeMX-STM32F103RCT6_单通道双路PWM互补输出
  9. 随机数的一些检测说明
  10. color balance (白平衡)