android graphic(21)—view tree的创建过程


view tree

下面这幅图是非常经典的view tree视图,其中叶子节点都是一个个实际的View,而ViewGroup作为View的容器,用来填充ViewGroup或者叶子节点View。

典型view tree

其中,各元素之间都有父子关系,这个父子关系在tree“遍历”的时候非常重要,从子到父,直到根节点(ViewRootImpl的performTraversals())

ViewParent是继承tree中的一个关键接口,定义了作为一个View的parent的所有职责,View用来和其parent交互。

/**
   ViewParent----
 * Defines the responsibilities for a class that will be a parent of a View.
 * This is the API that a view sees when it wants to interact with its parent.
 * 
 */

ViewGroup继承自View,实现了ViewParent。ViewRootImpl不算是一个View,因为没有继承View,但是实现了ViewParent接口,是该view tree的先祖,和window manager service做交互。

这里写图片描述

view tree的构成

下面分析一个view tree创建的过程,在http://blog.csdn.net/lewif/article/details/50735460中分析了activity申请surface的流程,其中主要包括:

1.当Activity调用完setContentView后,其成员mWindow,即PhoneWindow中现存的View如下图所示,

这里写图片描述

其中,DecorView(父)mDecor是一个FrameLayout,一个ViewGroup,用来“盛放”其他的view组件,例如mContentParent(子),而mContentParent(父)也是一个ViewGroup,用来“盛放”mView(子)。

这里写图片描述

下面简要分析下上述过程,利用setContentView()添加用户自定义的mView时,

    public void setContentView(View view, ViewGroup.LayoutParams params) {
        //① mContentParent开始肯定为空,首先执行 installDecor()
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
        //②将用户自己的mView添加到mContentParent这个ViewGroup
        mContentParent.addView(view, params);
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }
    private void installDecor() {
    if (mDecor == null) {
    //创建DecorView mDecor 
            mDecor = generateDecor();
            }
        //创建mContentParent ,输入为其父view,mDecor
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
    }

}

  protected ViewGroup generateLayout(DecorView decor) {

        View in = mLayoutInflater.inflate(layoutResource, null);
        //添加DecorView的子view
        decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    //contentParent 就是decor的子view
        ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
}
    public View findViewById(int id) {
        return getDecorView().findViewById(id);
    }

而decor.addView()和mContentParent.addView()最终会调用addViewInner(),在这里会去设置mDecor的子view、用户自定义view的父view为mContentParent。

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

            // tell our children
        if (preventRequestLayout) {
            child.assignParent(this);
        } else {
           //自定义mView的mParent为mContentParent
            child.mParent = this;
        }

        onViewAdded(child);

    }

2.在windowmanagerglobal的addView(decor)中,

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {

       //新建一个ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);

            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
    //将decor设置到ViewRootImpl中
    root.setView(view, wparams, panelParentView);

}
    /**
     * We have one child
     */
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
    //将decor的父view设置为ViewRootImpl
    view.assignParent(this);
  }
    void assignParent(ViewParent parent) {
        if (mParent == null) {
            mParent = parent;
        } else if (parent == null) {
            mParent = null;
        } else {
            throw new RuntimeException("view " + this + " being added, but"
                    + " it already has a parent");
        }
    }

所以经过上面的2步,最终形成的view tree如下图所示,从上到下依次是父子关系,而ViewRootImpl是祖先,用来和window manager service交互。

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值