AndroidView绘制流程一(View添加流程)

在Activity中,调用setContentView()方法,即可将自定义的View或者布局资源xml文件,添加至界面,那么setContentView()方法具体执行了哪些操作,view又是如何添加上去的呢。
进入Activity的setContentView()方法,发现其调用了getWindow().setContentView()方法,getWindow()返回的是Window对象,而该Window对象的唯一实现类是PhoneWindow。

    //Activity
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

进入PhoneWindow类,找到setContentView()方法,该方法中主要做了以下事情:
1)初始化顶层DecorView
2)创建父容器mContentParent,并添加至DecorView
3)解析传递的布局资源id,并将解析的view添加到contentParent中,从而完成view的添加。

 @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
        //注释1 此方法中初始化DecorView,创建父容器mContentParent
            installDecor();

        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            //注释4 这里解析layoutResID,并添加至mContentParent
            mLayoutInflater.inflate(layoutResID, mContentParent);

        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }
    private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            //注释2 这里初始化DecorView
            mDecor = generateDecor(-1);

            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            //注释3 这里创建mContentParent并添加至DecorView
            mContentParent = generateLayout(mDecor);

        }
    }

在注释1中,installDecor()方法中完成初始化DecorView以及创建父容器mContentParent,进入installDecor()方法,在注释2这里,对DecorView进行了初始化操作,在注释3这里,创建父容器mContentParent,并将mContentParent添加至顶层DecorView。这里我们查看一下mContentParent是如何被创建的,进入generateLayout()方法

 protected ViewGroup generateLayout(DecorView decor) {
        TypedArray a = getWindowStyle();
        //解析window属性
        if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
            requestFeature(FEATURE_NO_TITLE);
        } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
            requestFeature(FEATURE_ACTION_BAR);
        }
        //...
        //...
        //...
        // Inflate the window decor.
        //系统布局xml
        int layoutResource;
        int features = getLocalFeatures();
        //这里为layoutResource进行复制操作
        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
            layoutResource = R.layout.screen_swipe_dismiss;
            setCloseOnSwipeEnabled(true);
        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
            if (mIsFloating) {
                TypedValue res = new TypedValue();
                getContext().getTheme().resolveAttribute(
                        R.attr.dialogTitleIconsDecorLayout, res, true);
                layoutResource = res.resourceId;
            } else {
                layoutResource = R.layout.screen_title_icons;
            }
            removeFeature(FEATURE_ACTION_BAR);
            //...
            //...
            //...
        } else {
            layoutResource = R.layout.screen_simple;
        }

        mDecor.startChanging();
        //这里将解析的布局添加至DecorView
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        //系统布局中定义的FrameLayout设置的id:ID_ANDROID_CONTENT
        ViewGroup contentParent = (ViewGroup) findViewById(ID_ANDROID_CONTENT);
        if (contentParent == null) {
            throw new RuntimeException("Window couldn't find content container view");
        }
             //...
             //...
             //...
        mDecor.finishChanging();
        //返回已经初始化完成的父容器
        return contentParent;
    }

在该方法中,主要做了以下三件事:
1)解析window属性并设置
2)根据判定条件,找到相应的xml布局文件,并给layoutResource(资源文件ID)赋值,这里需要留意一点,在判定条件中出现的所有xml布局文件中,始终都会有ID 为ID_ANDROID_CONTENT即(com.android.internal.R.id.content)FrameLayout出现,该FrameLayout即父容器mContentParent。
这里我们以系统布局文件 screen_simple_overlay_action_mode.xml 为例,





    
    

在FrameLayout标签中,发现 android:id="@android:id/content",该ID即上述提到的ID_ANDROID_CONTENT。

返回至PhoneWindow类setContentView()方法中,在运行到注释4时,解析我们传递的布局xml文件,并添加到mContentParent中,至此完成View的添加。
AndroidView绘制流程一(View添加流程)_第1张图片

你可能感兴趣的:(Android)