由于經常會使用
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已經被添加了,不能再次被添加。同理,對于
View view = inflater.inflate(R.layout.dialog_kp_user_product_item, null);
也是如此,該方法一般再動态添加布局的時候用到,比如在動态添加布局時候,我們會用到此方法
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