前言
接上篇LayoutInflater 源码分析(一)之 inflate 深度分析
本篇继续对LayoutInflater进行源码分析,目标为分析LayoutInflater对include、merge、fragment等标签的处理原理以及onFinishInflate的调用时机。
merge 标签分析
上篇我们讲到inflate方法中出现 Merge 的踪迹,代码如下:
1 | if (TAG_MERGE.equals(name)) { |
所以需要看 rInflate方法才行。
rInflate 深入解析
1 | /** |
从注释来看rInflate方法,是个 递归方法 实例化 View 以及它的子 View,并且调用 onFinishInflate
从源码来看,rInflate方法先判断特殊的标签名,优先处理:
- 针对
requestFocus标签,调用parseRequestFocus方法 - 针对
tag标签,调用 parseViewTag 方法 - 针对
merge标签则直接抛了异常,因为merge标签不能是子元素
很奇怪,并没有看到 fragment 标签的处理逻辑!
处理完特殊标签之后走到最后一个else 块中,这块代码需要注意:
1 | // 如果不是特殊的标签那么走 createViewFromTag 获得 view |
这里涉及到一个方法rInflateChildren,其实它在上一篇中的inflate方法中出现过,不过我并没有去分析,所以这里讲一下。
方法实现如下:
1 | final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs, |
rInflateChildren 是个递归方法,被用来实例化不是 root 的子View,实际也是调用rInflate方法。(所以才是递归了嘛!)
这里需要注意的是finishInflate,按照之前所说的流程,rInflate方法传递过来的finishInflate参数为false,在上一篇中inflate传递的参数是true,这关系到onFinishInflate的回调。
了解完rInflateChildren方法后,继续分析。
可以看到,在处理merge标签的时候,是将merge标签里解析出来的 View 直接 add 到了传递进来的root中去了,而并不会多加一层 View,从而实现减少层级的效果,这就是merge标签的原理所在了。
最后,由于inflate传递进来的finishInflate为 false,所以不会去调用parent.onFinishInflate();
到此也知晓了LayoutInflater是如何处理merge标签以及merge减少布局层次的原理了。
include 标签
1 | private void parseInclude(XmlPullParser parser, Context context, View parent, |
首先判断 parent 是不是个 ViewGroup,如果不是则直接抛异常。
如果是则接下去处理 theme 属性以及 layout 属性,我们知道使用include标签,layout 属性是必须要有的。
其原因就是在源码中如果发现没有指定 layout 属性的话,那么会直接抛出异常。
再接下去的步骤可以看出其实跟上篇inflate方法类似:
- 通过调用
createViewFromTag解析获取被include的topview - 生成
params,这里要注意,include标签可能没有宽高,会导致生成失败,如果失败则接着又对被include的 topview 做操作。所以使用include的时候,不对它设置宽高是没有关系的。 - 调用
rInflateChildren处理子View 之前已经分析过 - 把
include标签的id以及visibility属性 设置给topview(如果有的话) topView被直接 add 进 group,这样被 include 的 topView 就被加到布局里去了。
小结
通过阅读源码,其实 merge 以及 include 等标签处理其实并不难,而且它们的使用方法在源码中皆有体现。
稍微总结一下要点:
- 使用 LayoutInflater 去 inflate merge 标签的时候,root 一定不能为 null,attachToRoot 也不能为 false
- merge标签在 XML 中必须是根元素
- 与 merge 标签相反,include 绝对不能是根元素,必须需要在一个 ViewGroup 中使用
- 使用 include 标签必须指定有效的 layout 属性
- 使用 include 标签不写宽高是没有关系的(会去解析被 include 的 layout)
到这里merge以及include已经分析完毕。
同时也看到了其他标签如tag、requestFocus的处理(很简单就不分析了),但是就是没看到fragment标签。
那究竟是在哪处理fragment标签的呢?
下一篇为你揭晓答案。
推荐阅读
一步一步深入理解CoordinatorLayout
LayoutInflater 源码分析(一)之 inflate 深度分析
LayoutInflater源码分析(二)之include以及merge标签的处理