setContentView源码解析

每次新建一个Activity时,我们都得将一个xml文件通过setContentView方法与这个Activity绑定在一起。那么,当我们调用setContentView时,是怎样一步一步创建这个界面的呢?

进入这个方法,我们会发现。通过getWindow调用进一步调用setContentView方法。getWindow方法会返回一个mWindow对象,而mWindow对象是在Activity的attach方法里进行初始化(mWindow = new PhoneWindow(this))。

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

下面看一下PhoneWindow中setContentView的源码

@Override
public void setContentView(int layoutResID) {
   
    if (mContentParent == null) {
        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 {
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

判断mContentParent是否为空,是空就调用installDecor方法进行初始化。不为null调用removeAllViews方法清除所有子View。最后调用mLayoutInflater.inflate(layoutResID, mContentParent)加载布局。下面在看下installDecor方法是怎么实现的

private void installDecor() {
    if (mDecor == null) {
        mDecor = generateDecor();
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    }
    if (mContentParent == null) {
        mContentParent = generateLayout(mDecor);

        // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
        mDecor.makeOptionalFitsSystemWindows();

        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);

        if (decorContentParent != null) {
            mDecorContentParent = decorContentParent;
            mDecorContentParent.setWindowCallback(getCallback());
            if (mDecorContentParent.getTitle() == null) {
                mDecorContentParent.setWindowTitle(mTitle);
            }

            final int localFeatures = getLocalFeatures();
            for (int i = 0; i < FEATURE_MAX; i++) {
                if ((localFeatures & (1 << i)) != 0) {
                    mDecorContentParent.initFeature(i);
                }
            }     
        }
    ........ 
    }
}

首先看 mDecor = generateDecor()这一步,很简单,在这里初始化了一个DecorView。接着下面会调用generateLayout方法,传入mDecor对mContentParent进行实例化。该方法较长,其主要内容是根据不同的情况加载不同的布局给layoutResource变量。在该代码中有一步layoutResource=R.layout.screen_title,这个布局是我们平时最常用的一个窗口布局;这一步的作用是将frameworks层的布局传入。

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:fitsSystemWindows="true">
        <FrameLayout
            android:layout_width="match_parent" 
            android:layout_height="?android:attr/windowTitleSize"
            style="?android:attr/windowTitleBackgroundStyle">
            <TextView android:id="@android:id/title" 
                style="?android:attr/windowTitleStyle"
                android:background="@null"
                android:fadingEdge="horizontal"
                android:gravity="center_vertical"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </FrameLayout>
        <FrameLayout android:id="@android:id/content"
            android:layout_width="match_parent" 
            android:layout_height="0dip"
            android:layout_weight="1"
            android:foregroundGravity="fill_horizontal|top"
            android:foreground="?android:attr/windowContentOverlay" />
    </LinearLayout>

猜你喜欢

转载自blog.csdn.net/qq_38256015/article/details/84191784