天天记录 - Android addView源码分析


    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?




你可能感兴趣的:(待整理)