上一篇从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绘制还没开始。