参考博客 http://blog.csdn.net/yanbober/article/details/45970721
LayoutInflater实例化获取的方法:
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 lif = LayoutInflater.from(Context context);
LayoutInflater lif = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
from方法仅仅是对getSystemService的一个安全封装而已。
得到LayoutInflater对象之后我们就是传递xml然后解析得到View,如下方法:
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();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
从上面可以看出真正的解析在方法 inflate(parser,root,attachToRoot)中
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
//获取parser中解析的属性集,比如什么TextView、Linearlayout这些
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context)mConstructorArgs[0];
mConstructorArgs[0] = mContext;
//定义返回值,初始化为传入的形参root
View result = root;
try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
//如果一开始就是END_DOCUMENT,那说明xml文件有问题
if (type != XmlPullParser.START_TAG) {
throw new InflateException(parser.getPositionDescription()
+ ": No start tag found!");
}
//有了上面判断说明这里type一定是START_TAG,也就是xml文件里的root node
final String name = parser.getName();
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}
if (TAG_MERGE.equals(name)) {
//处理merge tag的情况(merge,你懂的,APP的xml性能优化)
//root必须非空且attachToRoot为true,否则抛异常结束(APP使用merge时要注意的地方,
//因为merge的xml并不代表某个具体的view,只是将它包起来的其他xml的内容加到某个上层
//ViewGroup中。)
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
//递归inflate方法调运
rInflate(parser, root, attrs, false, false);
} else {
// Temp is the root view that was found in the xml
//xml文件中的root view,根据tag节点创建view对象
final View temp = createViewFromTag(root, name, attrs, false);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// Create layout params that match root, if supplied
//根据root生成合适的LayoutParams实例
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
//如果attachToRoot=false就调用view的setLayoutParams方法
temp.setLayoutParams(params);
}
}
if (DEBUG) {
System.out.println("-----> start inflating children");
}
// Inflate all children under temp
//递归inflate剩下的children
rInflate(parser, temp, attrs, true, true);
if (DEBUG) {
System.out.println("-----> done inflating children");
}
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
//root非空且attachToRoot=true则将xml文件的root view加到形参提供的root里
root.addView(temp, params);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
//返回xml里解析的root view
result = temp;
}
}
} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (IOException e) {
InflateException ex = new InflateException(
parser.getPositionDescription()
+ ": " + e.getMessage());
ex.initCause(e);
throw ex;
} finally {
// Don't retain static reference on context.
mConstructorArgs[0] = lastContext;
mConstructorArgs[1] = null;
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
//返回参数root或xml文件里的root view
return result;
}
}
给个个人总结就是上面代码就是通过判断Root 和AttachToRoot两个参数,当
inflate(xmlId, null); 只创建temp的View,就是只创建XML根节点的View,然后直接返回temp,但是由于不知道这个根节点View的容器ViewGroup是什么类型,所以这个根节点的Layout_....等的属性将被抛弃掉,即设置无效。
inflate(xmlId,root); 创建temp的View,然后执行root.addView(temp, params);最后返回root。这里的params是根据root类型生成的,别人说(类型为root.layoutparams这个参数不属于temp,它是root的一个内部类对象,不是很理解)但我觉得这样更好理解temp具有这个属性,但是类型不确定,即每一个view都有一个属性为viewgroup.layoutparams(虽说不科学)
inflate(xmlId, root, false); 创建temp的View,然后执行temp.setLayoutParams(params);然后再返回temp。根具root确定好params类型后,setLayoutParams(params)设置上面说的View的ViewGroup.LayoutParams属性,这样就可以把Layout_...等XML属性传给以后要添加的容器ViewGroup.
inflate(xmlId, parent, true); 创建temp的View,然后执行root.addView(temp, params);最后返回root。
inflate(xmlId, null, false); 只创建temp的View,然后直接返回temp。
inflate(xmlId, null, true); 只创建temp的View,然后直接返回temp。