setContentView(R.layout.activity_main)到底做了什么?

上一篇从SDK的源码中得知APP程序启动流程以及Activity的生命周期调用流程,但是我们会发现Activity中onCreate()方法中调用 setContentView(R.layout.activity_main)这么一句代码?猜测是将Activity对应的布局和Activity进行绑定。但是具体做了什么事尚不得知?那么还是的跟着SDK的源码走一遍才知道这句代码到底做了什么事?

1、找到Activity的类的setContentView方法
 /**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     *
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

Set the activity content from a layout resource. The resource will be inflated, adding all top-level views to the activity.
把一个布局资源设置到Activity内容,这个资源将会被加载解析,添加到Activity所有顶层的的视图上。

getWindow()得到的是Window是一个abstract class,那么需要找到Window 的具体实现类

/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.view.PhoneWindow, which you should instantiate when needing a
 * Window.
 */

The only existing implementation of this abstract class is android.view.PhoneWindow
唯一的实现类是android.view.PhoneWindow

2、找到android.view.PhoneWindow类的setContentView()
    @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        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();
        }
        mContentParentExplicitlySet = true;
    }

注意installDecor()、 mLayoutInflater.inflate(layoutResID, mContentParent)这个干了什么?

3、找到installDecor()的逻辑代码
if (mDecor == null) {
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }

mDecor是什么?

// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;

这是窗口的顶层视图,包含窗口装饰。这里说明DecorView是窗口的顶层视图。

接下来要注意一个参数mContentParent这个什么?

// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;

这是放置窗口内容的视图。它可以是mDecor本身,也可以是内容所在的mDecor的子元素。

那么mContentParent其实就是窗口内容的视图容器

接下来你会看到这么一句代码
mContentParent = generateLayout(mDecor);返回一个ViewGroup对象赋值给mContentParent,在generateLayout(mDecor)代码里面你会看到根据不同属性对应requestFeature的方法的调用,这里说明如果用户需要修改Feature样式属性需要在setContentView之前设置才有相应的效果。

接着你会在后面找到int layoutResource;这个参数是系统根据样式属性默认加载的系统的基础布局到mDecor上面

4、mLayoutInflater.inflate(layoutResID, mContentParent);逻辑代码

其实就是将资源文件xml进行解析然后加载到视图容器上

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
       return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
        if (DEBUG) {
            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                    + Integer.toHexString(resource) + ")");
        }

        final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }

到此就结束了,其实主要看的事情有三件1、加载布局容器2、加载系统基础布局3、加载自己的布局,至此自己的布局文件加载完成,但是UI绘制还没开始。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。