View inflate 原理

由於經常會使用 

View view = inflater.inflate(R.layout.fragment_main, container, false); 或者
View view = inflater.inflate(R.layout.dialog_kp_user_product_item,  null);

  兩個方法,但是不知道其有什麼區別?如果搞錯了會報

    Caused by: java.lang.IllegalStateException:The specified child already has a parent. You must call removeView() on the child's parent first.

 比如說我們在adapter ,把第三個參數改爲true, 在動態添加布局的時候把 null 改爲容器view,這樣就會出現上面的錯誤?原因是傳了true,表示立即把view 添加到viewGroup中,後面adapter 會再次把view 添加到viewGroup,這時候就會報錯說 illegalStateException, 因爲view已經被添加了,不能再次被添加。同理,對於

 

也是如此,該方法一般再動態添加布局的時候用到,比如在動態添加布局時候,我們會用到此方法

public void setLayout(View view){
        View subLayout = LayoutInflater.from(this).inflate(R.layout.sub_layout, null);
        mLinearLayout.addView(subLayout);
    }

這裏第二個參數傳了null,源碼追尋,

public void addView(View child, int index) {
        if (child == null) {
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }
        LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = generateDefaultLayoutParams();
            if (params == null) {
                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
            }
        }
        addView(child, index, params);
    }


public void addView(View child, int index, LayoutParams params) {
        if (DBG) {
            System.out.println(this + " addView");
        }

        if (child == null) {
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }

        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
        // therefore, we call requestLayout() on ourselves before, so that the child's request
        // will be blocked at our level
        requestLayout();
        invalidate(true);
        addViewInner(child, index, params, false);
    }

點擊addView,往下走,會看到 addView (View child, int index, LayoutParams params),添加之前會測量一遍,在刷新,最後add,我們點進去addViewInner ,

 private void addViewInner(View child, int index, LayoutParams params,
            boolean preventRequestLayout) {

        if (mTransition != null) {
            // Don't prevent other add transitions from completing, but cancel remove
            // transitions to let them complete the process before we add to the container
            mTransition.cancel(LayoutTransition.DISAPPEARING);
        }

        if (child.getParent() != null) {
            throw new IllegalStateException("The specified child already has a parent. " +
                    "You must call removeView() on the child's parent first.");
        }

        if (mTransition != null) {
            mTransition.addChild(this, child);
        }

        if (!checkLayoutParams(params)) {
            params = generateLayoutParams(params);
        }
        ......... 省略後面代碼

重點來了,if (child.getParant () != null) 時候拋出一個異常,而內容就是我們剛剛報的異常;這樣我們就明白了。inflater.inflate(R.layout.fragment_main, container, false) 打包 inflate 佈局的時候不能立即給view添加父佈局,否則會拋出異常。注意,這裏的表述不能立即給view添加父佈局,不是不添加,第三個參數 false 表示 延後添加,true 表示立即添加;同理,inflater.inflate(R.layout.dialog_kp_user_product_item, null);第二個參數爲空自然沒有父view ,也就不存在添加一說,當調用root.addView(subLayout)時候,root 會直接添加的,所以這裏就不應該再傳一個容器view,否則會添加,在調用addView的時候就會出錯。

總結:一般,添加view的職責是系統做的,當我們調用addView的時候,這個添加任務系統就會幫我們做掉。我們僅僅是需要提供一個view 佈局,通過inflate 實現,但是inflater 也能夠幫忙添加布局,所以在inflater 就不需要添加布局了。

 

個人愚見,如有不正,歡迎指出。


參考:https://stackoverflow.com/questions/12567578/what-does-the-layoutinflater-attachtoroot-parameter-mean/45809756#45809756

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章