获取实例
- 第一种方法
/**
* Obtains the LayoutInflater from the given context.
*/
public static LayoutInflater from(Context context) {
LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (LayoutInflater == null) {
throw new AssertionError("LayoutInflater not found.");
}
return LayoutInflater;
}
- 第二种方法
LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflate实例可以直接通过系统服务获取,第一种方法其实也是调用了第二种方法来获取实例。
inflate()
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 {
// 查找根节点
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 (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 xml中的根布局
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
......
// 创建根布局的参数
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// 设置参数值
temp.setLayoutParams(params);
}
}
......
// 在此context下填充所有子界面
rInflateChildren(parser, temp, attrs, true);
// 将所有子界面添加到root
if (root != null && attachToRoot) {
root.addView(temp, params);
}
// 确定返回值是传递过来的父界面还是xml解析出来的界面
if (root == null || !attachToRoot) {
result = temp;
}
}
} catch (XmlPullParserException e) {
} finally {
// 充值上下文信息
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
return result;
}
}
inflate方法共有四种,无论第一个参数传的resource还是parser,都是调用这个方法。总体思路是根据标签名和root值来确定解析方式,循环遍历节点,将子view添加到父布局,最后返回整个view。第26行,如果不是merge标签,调用rInflate(parser, root, inflaterContext, attrs, false)遍历解析子界面;否则,执行else代码块。循环遍历解析出view并添加到父布局,根据根布局是否为空确定返回值。第34行的createViewFromTag()是根据标签和属性创建view.第49行rInflateChildren()也是调用了rInflater(),只是和第一种情况参数不同。
rInflater()
void rInflate(XmlPullParser parser, View parent, Context context,
AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_TAG.equals(name)) {
parseViewTag(parser, parent, attrs);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, context, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
final View view = createViewFromTag(parent, name, context, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflateChildren(parser, view, attrs, true);
viewGroup.addView(view, params);
}
}
if (finishInflate) {
parent.onFinishInflate();
}
}
可以看到rInflate()是一层层递归解析xml标签并实例化view添加进父布局。第17、19和25行的方法殊途同归,最后都调用同一个方法,只是需求不同。最后else里面同样调用了createViewFromTag()和rInflaterChild()创建和添加view。
inflate()的参数问题
inflate(@LayoutRes int resource, @Nullable ViewGroup root)
inflate(XmlPullParser parser, @Nullable ViewGroup root)
inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)
第一个参数无论是resource还是parser最后都要用Pull方法来解析。root和attachToRoot是配合使用的,从inflate()的几行代码可以看出,如果root为null,那么attachToRoot参数就是去了意义。当root不为null且attachToRoot为true时,会将解析出的View加载进父布局。否则会将解析出的view直接返回。
if (root != null && attachToRoot) {
root.addView(temp, params);
}
if (root == null || !attachToRoot) {
result = temp;
}