本文使用android-28源码,路径:
/frameworks/base/core/java/android/view/LayoutInflater.java
入口:
Activity.setContentView(@LayoutRes int layoutResID)做了什么?
每个Activity都要设置一个布局:
1  | public void setContentView(@LayoutRes int layoutResID) {  | 
这里调用了getWindow().setContentView(layoutResID);,Window 类的实现类PhoneWindow。查看PhoneWindow的setContentView方法:
1  | public void setContentView(int layoutResID) {  | 
这里最终使用LayoutInflater加载布局。
LayoutInflater的使用只有一句话:
1  | LayoutInflater.from(mContext).inflate(resId, contentParent);  | 
可以分为两个部分:
LayoutInflater.from(mContext)通过mContext获取LayoutInflater对象inflate(resId, contentParent)将布局resId转化层View,加入contentParent中
获取LayoutInflater对象
1  | public static LayoutInflater from(Context context) {  | 
这里使用了getSystemService方法去获取LayoutInflater对象,所以进入ContextImpl类的getSystemService()方法:
1  | 
  | 
这里获取的是SystemServiceRegistry中的service,去SystemServiceRegistry中查找:
1  | static {  | 
可以看到,在SystemServiceRegistry类被加载的时候,在static静态块中注册了LAYOUT_INFLATER_SERVICE。这里直接返回了PhoneLayoutInflater类的对象,PhoneLayoutInflater是LayoutInflater的子类,在LayoutInflater的基础上重写了onCreateView方法,为系统自带的View添加前缀:
1  | private static final String[] sClassPrefixList = {  | 
所以,LayoutInflater.from(mContext)最终返回一个LayoutInflater的子类PhoneLayoutInflater的对象。
加载布局文件
LayoutInflater加载布局依靠inflate方法:
1  | public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {  | 
这里调用了inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)方法:
1  | public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {  | 
inflate方法的主体流程就是这些,这里主要看以下几个方法:
- 创建根布局的View:
createViewFromTag(root, name, inflaterContext, attrs); - 遍历创建子布局:
rInflateChildren(parser, temp, attrs, true); - 最终创建View的方法:
view = createView(name, prefix, attrs); 
创建根布局的View
1  | private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {  | 
这里的onCreateView(parent, name, attrs)和createView(name, null, attrs)的区别在于onCreateView使用了PhoneLayoutInflater重写的onCreateView方法,将系统View添加了前缀然后再使用createView方法进行创建View。
遍历创建子布局
1  | final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,  | 
这根布局下创建子布局的View通过在While循环下进行递归,一层一层的实现
最终创建View的方法
最终创建View的方法在createView中:
1  | public final View createView(String name, String prefix, AttributeSet attrs)  | 
从代码中可以看出,最终创建View是通过反射的方式创建,并且构造方法必须是两个入参的那种。
总结
- LayoutInflater的创建最终是一个PhoneLayoutInflater对象,只是通过SystemService在类加载的时候创建,并没有跨进程的操作。
 - LayoutInflater在解析布局文件的时候,是通过XmlResourceParser完成的。布局文件是一个树形结构,xml的解析就是一层层的解析,所以View的创建也是一层层创建,创建的时候使用递归的形式完成。
 - 在LayoutInflater中,View的创建是通过反射完成的,效率并不高;View反射创建的时候是通过调用View的两个入参的构造方法,所以在写自定义View的时候如果你的View要在布局文件中插入,就必须要重写View的两个入参的构造方法。