public View inflate(int resource, ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context)mConstructorArgs[0];
mConstructorArgs[0] = mContext;
View result = root;
try {
// 查找根节点
...
final String name = parser.getName();
if (TAG_MERGE.equals(name)) {
rInflate(parser, root, attrs, false, false);
} else {
//创建根View
final View temp = createViewFromTag(root, name, attrs, false);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
temp.setLayoutParams(params);
}
}
//递归创建子View
rInflate(parser, temp, attrs, true, true);
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}
}
return result;
}
}
过程大致如下:
- 首先根据layout的资源id,创建对应的XmlResouceParser
- XMLResourceParser找到根标签。
- 如果根标签不是merge的话,则通过createViewFromTag创建相应的View,然后递归的创建子View
- 如果设置了attachToRoot,则将将根View添加到rootView中,然后返回rootView;否则返回根view。
xml中根节点设置的layout_width和Layout_height有时不起作用,关键要看infalte时,是否传了rootView,并设置attachToRoot为true。
View createViewFromTag(View parent, String name, AttributeSet attrs, boolean inheritContext) {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
Context viewContext;
if (parent != null && inheritContext) {
viewContext = parent.getContext();
} else {
viewContext = mContext;
}
// 应用主题
final TypedArray ta = viewContext.obtainStyledAttributes(attrs, ATTRS_THEME);
final int themeResId = ta.getResourceId(0, 0);
if (themeResId != 0) {
viewContext = new ContextThemeWrapper(viewContext, themeResId);
}
ta.recycle();
try {
View view;
if (mFactory2 != null) {
view = mFactory2.onCreateView(parent, name, viewContext, attrs);
} else if (mFactory != null) {
view = mFactory.onCreateView(name, viewContext, attrs);
} else {
view = null;
}
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, viewContext, attrs);
}
if (view == null) {
final Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = viewContext;
try {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs);
} else {
view = createView(name, null, attrs);
}
} finally {
mConstructorArgs[0] = lastContext;
}
}
return view;
}
依次分别由mFactory2、mFactory、mPrivateFactory创建View,如果都没有创建,则由LayoutInflater自己创建。
下面看看LayoutInflater是如何创建的
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor extends View> constructor = sConstructorMap.get(name);
Class extends View> clazz = null;
try {
if (constructor == null) {
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
constructor = clazz.getConstructor(mConstructorSignature);
sConstructorMap.put(name, constructor);
} else {
Object[] args = mConstructorArgs;
args[1] = attrs;
constructor.setAccessible(true);
final View view = constructor.newInstance(args);
return view;
}
LayoutInflater内有View构造函数的缓存,当存在该View的构造函数时,直接拿来创建实例,否则通过context.getClassLoader,由classLoader去loadClass,然后获得该类的构造函数,并存入缓存,然后调用构造函数创建View。
那mFactory2、mFactory和mPrivateFactory是用来干什么的呢?它们之间是什么关系?这三个变量是何时被赋值的?
第一个问题的答案是,可以对LayoutInflater从xml中创建View的过程进行扩展。
对于第二个问题,来看一下Factory和Factory2的定义
public interface Factory {
public View onCreateView(String name, Context context, AttributeSet attrs);
}
public interface Factory2 extends Factory {
public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
}
Factory2继承于Factory,增加了一个接口。其中mFractory是Factory类型的,mFactory2和mPrivateFactory是Factory2类型的。你要是去看Android源码修改日志的话,可以看到最初的时候只有mFactory,后来为了支持Fragment才增加了mFactory2,后来又有了mPrivateFactory。
之所以还留着Factory,是为了向下兼容。
第三个问题,三个Factory是何时被赋值的?
如果看一下Activity的定义的话,你会发现Activity实现了Factory2接口。并且在attach方法中,将自己设置为LayoutInflater的privateFactory。
mWindow.getLayoutInflater().setPrivateFactory(this);
这是你就会明白了,当我们使用LayoutInflater来inflate View的时候,首先会走到Activity的onCreateView中,如果返回了null,才会由LayoutInflater继续创建View。我们来看一下Activity的onCreateView是如何实现的
public View onCreateView(String name, Context context, AttributeSet attrs) {
return null;
}
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
if (!"fragment".equals(name)) {
return onCreateView(name, context, attrs);
}
return mFragments.onCreateView(parent, name, context, attrs);
}
如果是fragment的话,则由mFragments去创建,否则返回null。
而mFragments的类型是FragmentManagerImpl。
这样就说的通了,以前的时候Android是不支持Fragment的,View都由LayoutInflater直接创建,后来为了支持Fragment,让Activity来实现Factory2,从而拦截对Fragment的创建,后来又把Fragment相关的代码移到了FragmentManager中。
这时候你可以会说,我用的不是Activity,而是FragmentActivity。
在BaseFragmentActivityDonut代码中
protected void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT < 11 && getLayoutInflater().getFactory() == null) {
getLayoutInflater().setFactory(this);
}
super.onCreate(savedInstanceState);
}
如果系统Build版本小于11,LayoutInflater的mFactory被设置为Activity,而11之后,则是mPrivateFactory被设置为Activity。