LayoutInflater.inflate()解析

布局加载器加载视图的方法有以下几种:

  1. public View inflate(int resource, ViewGroup root)
  2. public View inflate(int resource, ViewGroup root, boolean attachToRoot)
  3. public View inflate(XmlPullParser parser, ViewGroup root)
  4. public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)

resource会通过Pull解析器被解析成XmlPullParser类型的parser, 故只需要看第四个方法就知道是怎么回事了!一般我们使用它的时候有三种使用方法:

  1. inflate(parser, null, false);
  2. inflate(parser, root, false);
  3. inflate(parser, root, true);

//在API25源码复制
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 {
            // 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)) {
                if (root == null || !attachToRoot) {
                    throw new InflateException(" can be used only with a valid "
                            + "ViewGroup root and attachToRoot=true");
                }

                rInflate(parser, root, inflaterContext, attrs, false);
            } else {
                // 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);
                    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) {
            final InflateException ie = new InflateException(e.getMessage(), e);
            ie.setStackTrace(EMPTY_STACK_TRACE);
            throw ie;
        } catch (Exception e) {
            final InflateException ie = new InflateException(parser.getPositionDescription()
                    + ": " + e.getMessage(), e);
            ie.setStackTrace(EMPTY_STACK_TRACE);
            throw ie;
        } finally {
            // Don't retain static reference on context.
            mConstructorArgs[0] = lastContext;
            mConstructorArgs[1] = null;

            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }

        return result;
    }
}
  1. inflate(parser, null, false);
  2. inflate(parser, root, false);
  3. inflate(parser, root, true);

第一种情况:

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

temp是啥?往前看:

// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);

temp is the root view that was found in the xml.源码中的注释写的很清晰。temp就是你加载的那个xml文件的根视图。也就是说第二个参数root如果是空就直接返回xml文件里的根视图。接下来看看root!=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);
    if (!attachToRoot) {
        // Set the layout params for temp if we are not
        // attaching. (If we are, we use addView, below)
        temp.setLayoutParams(params);
    }
    ...

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


}

现在更清晰了,当我们传进来的root不是null,并且第三个参数是false的时候,这个temp会使用root生成的layoutParams,并作为返回值返回了。而当我们设置root为空的时候,没有设置LayoutParams参数的temp对象,作为返回值返回了。这时候我们发现只要是root为null或者attachToRoot为false都会将root返回,那么inflate(parser, null, false)和inflate(parser, root, false)又有什么区别呢?实际上这个root是作为一个协助生成view的容器,如果我想让生成的布局的根节点有效,又不想让它处于某一个容器中,那我就可以设置root!=null,而attachToRoot为false。由此可见root会协助第一个参数所指定布局的根节点生成布局参数!
  再回头看代码,当root!=null,attachToRoot为true时:

// 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);
}

很清楚,当attachToRoot为true时,会将第一个参数所指定的布局添加到第二个参数的View中。
  总结一下:当root==null时,直接返回要加载布局文件的根视图;当root!=null时,如果attachToRoot==false,系统会通过将root作为一个容器,协助生成view;如果attachToRoot==true,会将生成的view添加到root中。

你可能感兴趣的:(LayoutInflater.inflate()解析)