您的位置:首页 > 其它

LayoutInflater 到底怎么把xml添加到decorview

2017-05-14 21:10 369 查看
LayoutInflater 到底怎么把xml添加到decorview

      Actity调用setContentView时初始化decorview后会根据layoutResID加载布局。

  

     下面是源码加载过程:

     PhoneWindow.java:      

@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}

if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}


              LayoutInflater.java:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
//将布局id和容器id传入
return inflate(resource, root, root != null);
}

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
//根据layoutId获取xml解析器
final XmlResourceParser parser = res.getLayout(resource);
try {
//将xml解析器和ViewGroup容器、是否加载到根节点下传入 inflate方法中
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}

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; //把(contentPerent)ViewGroup赋值给result

try {
// Look for the root node. 寻找根节点
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 (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
+ name);
System.out.println("**************************");
}

if (TAG_MERGE.equals(name)) {//判断根节点是否为merge标签
if (root == null || !attachToRoot) {//判断root是否为空,merge必须添加到ViewGroup里
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}

rInflate(parser, root, inflaterContext, attrs, false);
} else {//当根节点不是merge标签时
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);//生成根节点

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
params = root.generateLayoutParams(attrs);//调用content的FrameLayout的属性解析
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params);//添加属性到已创建的根节点上
}
}

if (DEBUG) {
System.out.println("-----> start inflating children");
}

// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, 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.addView(temp, params);
}

// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
}

} catch (XmlPullParserException e) {
InflateException ex = new InflateException(e.getMessage());
ex.initCause(e);
throw ex;
} catch (Exception 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);

return result;
}
}

final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}

/**
* Recursive method used to descend down the xml hierarchy and instantiate
* views, instantiate their children, and then call onFinishInflate().
* <p>
* <strong>Note:</strong> Default visibility so the BridgeInflater can
* override it.
*/
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)) {//如果标签名为include
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");//include 标签不能作为根节点
}
parseInclude(parser, context, parent, attrs);
} else if (TAG_MERGE.equals(name)) {//如果标签名为merge
throw new InflateException("<merge /> must be the root element"); //merge标签只能作为根节点 //merge标签加载后会减少节点层级
} 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);
}
}

//解析merge标签时finishInflate为true

if (finishInflate) {
parent.onFinishInflate();

} }

LayoutInflater解析的过程图,通过深度优先遍历:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐