android inflate加載佈局幾種寫法的區別+源碼分析

image.png

從上圖能夠看到 inflate 方法有四個重載方法,有兩個方法第一個參數接收的是一個佈局文件id,另外兩個接收的是XmlPullParse,看源碼就知道,接收佈局文件的inflate方法裏面調用的是接收XmlPullParse的方法。 bash

image.png
所以,咱們通常只調用接收佈局文件ID的inflate方法。兩個重載方法的區別在於有無第三個參數attachToRoot, 而從源碼裏裏面能夠看到,兩個參數的方法最終調用的是三個參數的inflate方法:
image.png
第三個參數的值是根據第二個參數的值來判斷的。

所以咱們只須要分析一下三個參數的inflate方法,看一下這個方法的定義:ide

/**
     * 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信息。 ###源碼分析ui

....
          //前面省略
          //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;
        }
複製代碼

從上面這段代碼就能很清楚的說明前面提到的兩種加載方式的區別了。this

第一種加載方式 root爲 null :源碼中的代碼在 解釋1解釋6 直接返回的就是從xml加載的temp View。spa

第二種加載方式 root不爲null ,attachToRoot 爲false: 源碼中在 解釋3解釋5 ,爲temp 設置了經過root生成的LayoutParams信息,可是沒有add 添加到root 。code

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

相關文章
相關標籤/搜索