Android LayoutInflater
参考文章
Android LayoutInflater原理分析,带你一步步深入了解View(一)
请直接观看上面的文章。下面的可以不必看。
记录
LayoutInflater 的作用就是将XML布局文件实例化为相应的 View 对象
总结
- LayoutInflater的内部实现方式,主要是pull解析布局文件
- attachToRoot参数作用
-
root != null, attachToRoot == true
传进来的布局会被加载成为一个View并作为子View添加到root中,最终返回root;
而且这个布局根节点的android:layout_xxx参数会被解析用来设置View的大小; -
root == null, attachToRoot无意义
当root为空时,attachToRoot无论是什么都没有意义。此时传进来的布局会被加载成为一个View并直接返回;
布局根View的android:layout_xxx属性会被忽略,即android:layout_xx属性只有依附在某个ViewGroup中才能生效; -
root != null, attachToRoot == false
传进来的布局会被加载成为一个View并直接返回。
布局根View的android:layout_xxx属性会被解析成LayoutParams并设置在View上,此时root只用于设置布局根View的大小和位置。
-
通过标签以反射的方式来创建 View 对象;
-
加载xml布局的原理
其实就是从根节点开始,递归解析xml的每个节点,每一步递归的过程是:通过节点名称(全类名),使用ClassLoader创建对应类的实例,也就是View,然后,将这个View添加到它的上层节点(父View)。并同时会解析对应xml节点的属性作为View的属性。每个层级的节点都会被生成一个个的View,并根据View的层级关系add到对应的直接父View(上层节点)中,最终返回一个包含了所有解析好的子View的布局根View。
为什么view嵌套view多了会造成卡顿?
public void setContentView(int resId) {
this.ensureSubDecor();
ViewGroup contentParent = (ViewGroup)this.mSubDecor.findViewById(16908290);
contentParent.removeAllViews();
LayoutInflater.from(this.mContext).inflate(resId, contentParent);
this.mOriginalWindowCallback.onContentChanged();
}
setContentView方式内部也是使用LayoutInflater把布局加入到FrameLayout布局中的,而根据上面两篇文章,说到
void rInflate(XmlPullParser parser, View parent, Context context,
AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
boolean pendingRequestFocus = false;
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)) {
pendingRequestFocus = true;
consumeChildElements(parser);
} 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 (pendingRequestFocus) {
parent.restoreDefaultFocus();
}
if (finishInflate) {
parent.onFinishInflate();
}
}
这个方式使用了递归算法,在这里
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);
}
如果嵌套层次过多,是会造成显示过慢。
当然使用LayoutInflater只是卡顿众多原因的一个,还有View的测量和绘制都是递归实现的。