Android把视图显示到屏幕上,从代码角度最终都是调用ViewGroup.addView方法,可以分为两类,一是初始化时添加视图,二是动态添加视图。
1. 从源码角度分析添加视图的流程,以下列出其中4个addView方法
public void addView(View child) { addView(child, -1); } public void addView(View child, int index) { 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 width, int height) { final LayoutParams params = generateDefaultLayoutParams(); params.width = width; params.height = height; addView(child, -1, params); } public void addView(View child, LayoutParams params) { addView(child, -1, params); }
2. 以上4个addView方法其最终都会调用以下方法,实现具体操作
/** * Adds a child view with the specified layout parameters. * * @param child the child view to add * @param index the position at which to add the child * @param params the layout parameters to set on the child */ public void addView(View child, int index, LayoutParams params) { if (DBG ) { System. out.println(this + " addView"); } // 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 // 为什么调用invalidate还调用requestLayout? requestLayout(); invalidate(); // 为什么先requestLayout, invalidate之后才向ViewGroup中添加View? addViewInner(child, index, params, false); }
3. 调用ViewGroup.addViewInner
private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) { // 此View是否已经添加 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 (!checkLayoutParams(params)) { params = generateLayoutParams(params); } if (preventRequestLayout) { child.mLayoutParams = params; } else { // 前面注释提到的,请求requestLayout child.setLayoutParams(params); } // 如果传入-1,直接添加到最后 if (index < 0) { index = mChildrenCount; } // 添加到ViewGroup addInArray(child, index); // tell our children if (preventRequestLayout) { child.assignParent( this); } else { // 指定添加view的父视图 child.mParent = this; } if (child.hasFocus()) { requestChildFocus(child, child.findFocus()); } AttachInfo ai = mAttachInfo; if (ai != null) { boolean lastKeepOn = ai.mKeepScreenOn; ai.mKeepScreenOn = false; // AttachInfo 与 View建立联系 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK)); if (ai.mKeepScreenOn) { needGlobalAttributesUpdate( true); } ai.mKeepScreenOn = lastKeepOn; } // 可以通过此监听器获得是否有新View被添加 if (mOnHierarchyChangeListener != null) { mOnHierarchyChangeListener .onChildViewAdded(this, child); } if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE ; } }
疑问:
1. 为什么调用invalidate还调用requestLayout?
2. 为什么先requestLayout, invalidate之后才向ViewGroup中添加View?