Android

对 inflate 你真的了解吗?

inflate(resource, root) 相当于 inflate(resource, root, root!=null) , 而后者的返回值由root决定,如果root不为空,会把root的布局信息设给xml对应的view,如果同时attachToRoot还是true,则把View添加到root里面,然后返回root,如果不是,最后返回xml对应的View!

结论如上,现在,我们一步步来看下,首先看四行代码:

public View inflate(int resource, ViewGroup root)

public View inflate(int resource, ViewGroup root, boolean attachToRoot)

public View inflate(XmlPullParser parser, ViewGroup root)

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)

其中,1和2我们平时很常见,但核心是4,无论1还是2,最终都调用4,3也调用4!请看原码:

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
    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) + ")");
  }

  final XmlResourceParser parser = res.getLayout(resource);
  try {
      return inflate(parser, root, attachToRoot);
  } finally {
      parser.close();
  }
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
    return inflate(parser, root, root != null);
}
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("<merge /> 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段代码调用第2段代码,第2段代码调用第4段代码,当然,第3段代码也调用第4段代码!对于第4段代码,它返回result,而result最初赋值root,然后再看root,相关的核心代码有2段,先看第一段:

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

这里如果root不为空,则把root的布局信息设给xml的布局,上面的tmp便是xml文件对应的view!

现在看第二段:

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

这里,如果root不为null,而且attachToRoot,则把tmp添加到root里面,如果不是则把tmp赋值给result,最后返回result!这里的attachToRoot便是上文刚开始时提到的attachToRoot经过查看这段原码,我们得出这样的结论:

inflate(resource, root) 相当于 inflate(resource, root, root!=null) , 而后者的返回值由root决定,如果root不为空,会把root的布局信息设给xml对应的view,如果同时attachToRoot还是true,则把View添加到root里面,然后返回root,如果不是,最后返回xml对应的View!

full-stack-trip

Share
Published by
full-stack-trip

Recent Posts

Android 自定义 View 入门

说来惭愧,工作数年,连基本的自…

4 年 ago

retrofit 同时支持 xml 和 json

retrofit 解析 jso…

4 年 ago

mysql - 存储过程 从入门到放弃

最近有个报表的需求,于是乎用了…

4 年 ago

奶嘴战略 - 你不得不知道的扎心真相(一)

一句:英雄枯骨无人问,戏子家事…

4 年 ago

acme.sh 的简单使用

acme.sh 是纯 shel…

4 年 ago

wrk -更现代化的http压测工具

wrk 是一款更现代化的 ht…

4 年 ago