Android Activity 的构成 [基于android 8 源码]
setContentView到底做了什么
打开Activity.java,找到 其中的一个 setContentView,他的参数为 int layoutResID。
/**
* 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();
}
@LayoutRes 是java的注解,请参考 http://www.cnblogs.com/gmq-sh/p/4798194.html
来看第一行 的 getWindow:
/**
* Retrieve the current {@link android.view.Window} for the activity.
* This can be used to directly access parts of the Window API that
* are not available through Activity/Screen.
*
* @return Window The current window, or null if the activity is not
* visual.
*/
public Window getWindow() {
return mWindow;
}
看起来是直接返回了 mWindow , 他的类型是 Window。
那么他是怎么被创建出来的呢? 继续在 Activity.java中查找发现:
final void attach(...)
{
mWindow = new PhoneWindow(this, window, activityConfigCallback);
}
所以转到 PhoneWindow 的 setContentView:
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
...
}
private void installDecor() {
mForceDecorInstall = false;
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 的类型是 DecorView, 这个view就是Activity的根View,他声明在 PhoneWindow里面:
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
mDecor = generateDecor(-1);
protected DecorView generateDecor(int featureId) {
...
return new DecorView(context, featureId, this, getAttributes());
}
然后 在PhoneWindow的 installDecor 中拿到 mDecor之后, 会call
mContentParent = generateLayout(mDecor);
generateLayout 主要做这两件事情:1. 加载布局, 2. 配置布局给 layoutResource
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
// Inflate the window decor.
}
这样就形成了下面这么一个布局:详情可以看 screen_title.xml的内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<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>