从上图可以看到 inflate 方法有四个重载方法,有两个方法第一个参数接收的是一个布局文件id,另外两个接收的是XmlPullParse,看源码就知道,接收布局文件的inflate方法里面调用的是接收XmlPullParse的方法。

因此,我们一般只调用接收布局文件ID的inflate方法。两个重载方法的区别在于有无第三个参数attachToRoot, 而从源码里里面可以看到,两个参数的方法最终调用的是三个参数的inflate方法: 第三个参数的值是根据第二个参数的值来判断的。

因此我们只需要分析一下三个参数的inflate方法,看一下这个方法的定义:

/**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        <code>R.layout.main_page</code>)
     * @param root Optional view to be the parent of the generated hierarchy (if
     *        <em>attachToRoot</em> is true), or else simply an object that
     *        provides a set of LayoutParams values for root of the returned
     *        hierarchy (if <em>attachToRoot</em> is false.)
     * @param attachToRoot Whether the inflated hierarchy should be attached to
     *        the root parameter? If false, root is only used to create the
     *        correct subclass of LayoutParams for the root view in the XML.
     * @return The root View of the inflated hierarchy. If root was supplied and
     *         attachToRoot is true, this is root; otherwise it is the root of
     *         the inflated XML file.
     */
    public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)

复制代码

解释:从指定的xml资源文件加载一个新的View,如果发生错误会抛出InflateException异常。 参数解释: resource:加载的布局文件资源id,如:R.layout.main_page。 root:如果attachToRoot(也就是第三个参数)为true, 那么root就是为新加载的View指定的父View。否则,root只是一个为返回View层级的根布局提供LayoutParams值的简单对象。 attachToRoot: 新加载的布局是否添加到root,如果为false,root参数仅仅用于为xml根布局创建正确的LayoutParams子类(列如:根布局为LinearLayout,则用LinearLayout.LayoutParam)。

了解了这几个参数的意义后,我们来看一下前面提到的两种写法 #####第一种:root 为null

View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.inflate_test_item,null)
复制代码

这可能是我们用得比较多的一种方式,直接提供一个布局,返回一个View,根据上面的几个参数解释就知道,这种方式,没有指定新加载的View添加到哪个父容器,也没有root提供LayoutParams布局信息。这个时候,如果调用view.getLayoutParams() 返回的值为null。通过上面的测试,我们知道这种方式会导致RecyclerView Item 布局宽高失效。具体原因稍后再分析。 #####第二种:root不为null,attachToRoot为false

View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.inflate_test_item,parent,false)
复制代码

这种方式加载,root不为null,但是attachToRoot 为 false,因此,加载的View不会添加到root,但是会用root生成的LayoutParams信息。 ###源码分析

....
          //前面省略
          //result是最终返回的View
          View result = root;

            try {
               ...
               // 省略部分代码
               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 {

                   // 重点就在这个else代码块里了
                    //解释1:首先创建了xml布局文件的根View,temp View 

                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                    ViewGroup.LayoutParams params = null;
                   // 解释2:判断root是否为null,不为null,就通过root生成LayoutParams
                    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);
                        // 解释3:如果在root不为null, 并且attachToRoot为false,就为temp View(也就是通过inflate加载的根View)设置LayoutParams.
                        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");
                    }
                     //解释4:加载根布局temp View 下面的子View

                    rInflateChildren(parser, temp, attrs, true);

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

                    //解释5: 注意这一步,root不为null ,并且attachToRoot 为true时,才将从xml加载的View添加到root.
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }

                    // 解释6:最后,如果root为null,或者attachToRoot为false,那么最终inflate返回的值就是从xml加载的View(temp),否则,返回的就是root(temp已添加到root)
                    if (root == null || !attachToRoot) {
                        result = temp;
                    }
                }

            }

            ...
            //省略部分代码
            return result;
        }
复制代码

从上面这段代码就能很清楚的说明前面提到的两种加载方式的区别了。

第一种加载方式 root为 null :源码中的代码在 解释1解释6 直接返回的就是从xml加载的temp View。

第二种加载方式 root不为null ,attachToRoot 为false: 源码中在 解释3解释5 ,为temp 设置了通过root生成的LayoutParams信息,但是没有add 添加到root 。

参考文章:www.jianshu.com/p/9a6db88b8…