前言
每天都在使用LayoutInflater,是否了解过其内部实现呢?今天,就来学习下,是如何从xml文件加成成View的。
LayoutInflater#inflate
不管是通过什么方式去加载的,最后都会调用inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)这个方法。这个方法的代码如下:
|
|
代码较长,主要逻辑如下:
- 从XmlPullParser中的到AttributeSet,设置View的构造函数的第一个参数context
- 判断标签类型
- merge标签,用rInflate进行解析加载
- 其他,通过createViewFromTag方法,创建xml文件的根节点的view,然后通过rInflateChildren方法解析根view中包含的子view,并根据参数将其add到root view中。
逻辑还是比较清晰的,从上面的步骤中,我们能知道几个重要的方法,分别是:
- createViewFromTag 创建root view
- rInflate解析merge标签的view
- rInflateChildren解析ViewGroup中的子View
LayoutInflater#createViewFromTag
那么,我们先来看下,root view是如何创建出来的。代码如下:
|
|
- 首先获取View的name
- 根据参数,应用主题
- TAG_1995?这个没怎么看懂
- 根据mFactory2,mFactory,mPrivateFactory等是否设置过,来通过这些去加载View,我们经常在一些换肤框架中能见到。
- 如果都没有的话,就判断name中是否包含.,为啥要这样呢?就是根据玩这个路径去加载类,然后构造View。
- 通过代码能够发现,onCreateView方法内部也会调用createView方法,不过会加android.view.拼成完整的路径。
LayoutInflater#createView
系统通过这个方法来构造View对象,我们就看下它的具体实现。
|
|
代码虽然长,但是从逻辑上分为两个部分。
- 已经缓存过构造函数
- 未缓存过构造函数
在学习源码的过程中,我们经常能见到这种内存缓存的设计,以空间换时间的方法来提升效率。这个技能,我们需要get到。
这里我们只看没有缓存过的部分。逻辑如下:
- 通过classloader加载Class
- 通过参数获取对应的构造方法,并进行缓存
- 通过构造方法构造View对象
- 如果是ViewStub的话,因为这里是按需加载,所以我们需要将这个Context对象设置给他。
通过上面一系列方法就成功的根据xml文件构建出来root view了。当然普通view的构造过程也是一样的。
LayoutInflater#rInflate
|
|
final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}
```
这里调用rInflate去解析,略过
就这样,就从xml解析成View了。
剩下的一点东西
- Filter
- Factory
- Factory2
上面的几个接口,允许我们去做一些过滤操作,或者我们控制下View的构造过程。
总结
逻辑上很清晰,不知道大家有没有学习到呢?