onCreate() 在哪里被调用
要想知道 onCreate() 在哪里调用,首先就要来看一下 Activity 在哪里被创建。先来找一下 app 的 main() 方法,在 ActivityThread 类中
public static void main(String[] args) {
...
ActivityThread thread = new ActivityThread();
...
}
在 main() 方法中会创建 ActivityThread 类,我们再来找一下 ActivityThread 类的 handleLaunchActivity() 方法
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
}
在 3409 行,我们看到在 handleLaunchActivity() 中调用了 performLaunchActivity() 返回了一个 Activity ,这里就创建出了我们的 Activity 对象了。那 onCreate() 在哪里被调用呢,我们点进 performLaunchActivity() 看一下,在 3183 行有这么一行代码
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
Activity 的创建有交给了 Instrumentation 这个类,继续往下看 在 3243 行
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
mInstrumentation.callActivityOnCreate() 在这个方法里会去调用 Activity 的 onCreate(),到这了 Activity 的 onCreate() 就会被调用。当然我们还可以看一下 Activity 的其它一些方法 handleStartActivity() 会对应的调用 onStart() 方法,handleResumeActivity 会对应调用 onResume()。
setContentView() 做了些什么
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
setContentView() 最后会去执行到 AppCompatDelegateImpl类 的 setContentVeiw()
@Override
public void setContentView(int resId) {
ensureSubDecor();
ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
contentParent.removeAllViews();
LayoutInflater.from(mContext).inflate(resId, contentParent);
mAppCompatWindowCallback.getWrapped().onContentChanged();
}
这几句代码就很熟悉了,通过 findViewById 找到一个 contentParent 然后通过 inflate() 把我们写的布局文件实例化成 View 并添加到 contentParent 中,到这了我们的 Activity 的所有 View 都实例化出来了,但是光创建出对象是没用的,因为这些 View 的布局和测量还没有发生,所以我们在 onCreate() 中是不能直接获取到某个 view 的宽高的。
mSubDecor 布局结构是什么样的
在看 Activity 的绘制流程之前我们先看一下 mSubDecor 的布局是什么样的。打开 ensureSubDecor()
private void ensureSubDecor() {
...
mSubDecor = createSubDecor();
...
}
再看一下 createSubDecor()
private ViewGroup createSubDecor() {
...
ensureWindow();
mWindow.getDecorView();
...
ViewGroup subDecor = null;
...
if (!mWindowNoTitle) {
if (mIsFloating) {
...
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_dialog_title_material, null);
} else if (mHasActionBar) {
...
// Now inflate the view using the themed context and set it as the content view
subDecor = (ViewGroup) LayoutInflater.from(themedContext)
.inflate(R.layout.abc_screen_toolbar, null);
}
} else {
if (mOverlayActionMode) {
subDecor = (ViewGroup) inflater.inflate(
R.layout.abc_screen_simple_overlay_action_mode, null);
} else {
subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null);
}
}
...
final ContentFrameLayout contentView = (ContentFrameLayout) subDecor.findViewById(
R.id.action_bar_activity_content);
final ViewGroup windowContentView = (ViewGroup) mWindow.findViewById(android.R.id.content);
if (windowContentView != null) {
...
windowContentView.setId(View.NO_ID);
contentView.setId(android.R.id.content);
...
}
mWindow.setContentView(subDecor);
...
return subDecor;
}
首先会根据不同的配置 subDecor 会 inflate 不同的布局,一般我们的 Activity 会加载 R.layout.abc_screen_simple 这个布局,打开 sdk 找到这个布局文件
<androidx.appcompat.widget.FitWindowsLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true">
<androidx.appcompat.widget.ViewStubCompat
android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/abc_action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
// 这里把 include 的布局直接贴出来
// <include layout="@layout/abc_screen_content_include" />
<androidx.appcompat.widget.ContentFrameLayout
android:id="@id/action_bar_activity_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</androidx.appcompat.widget.FitWindowsLinearLayout>
上面的 contentView.setId(android.R.id.content) 这行代码会吧 action_bar_activity_content 这个 id 替换成 R.id.content,所以上面我们 会吧 setContentView(resId) 传入的布局添加到这个 ContentFrameLayout 中,mSubDecor 就是这个 FitWindowsLinearLayout。
mWindow 实现类是什么,在哪里初始化的
上面的 subDecor 创建后会调用 mWindow.setContentView(subDecor) ,mWindow 在哪里被创建的呢。我们看一下 ensureWindow()
private void ensureWindow() {
if (mWindow == null && mHost instanceof Activity) {
attachToWindow(((Activity) mHost).getWindow());
}
...
}
private void attachToWindow(@NonNull Window window) {
...
mWindow = window;
}
public Window getWindow() {
return mWindow;
}
在 attachToWindow() 中会给 mWindow 赋值,ensureWindow 会调用 Activity 的 getWindow() ,最后返回的是 Activity 的成员变量 mWindow。回到上面的 onCreate 方法调用的地方,也就是 performLaunchActivity() 方法中
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
...
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
return activity;
}
Activity 被创建之后首先调用 attach() 初始化 Activity
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
mWindowManager = mWindow.getWindowManager();
...
}
这里可以看到 mWindow 是 PhoneWindow 对象,找到 setContentView()
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
}
...
mContentParent.addView(view, params);
...
}
这里会把上面创建的 subDecor 添加到 mContentParent 中,现在找一下 mContentParent 在哪里被初始化的,打开 installDecor() 方法
private void installDecor() {
...
if (mDecor == null) {
mDecor = generateDecor(-1);
}
...
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
...
}
protected DecorView generateDecor(int featureId) {
...
return new DecorView(context, featureId, this, getAttributes());
}
protected ViewGroup generateLayout(DecorView decor) {
...
int layoutResource;
int features = getLocalFeatures();
if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
layoutResource = R.layout.screen_swipe_dismiss;
} 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 if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
layoutResource = R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_custom_title;
}
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
layoutResource = a.getResourceId(
R.styleable.Window_windowActionBarFullscreenDecorLayout,
R.layout.screen_action_bar);
} else {
layoutResource = R.layout.screen_title;
}
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
layoutResource = R.layout.screen_simple;
}
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
...
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
...
return contentParent;
}
generateDecor() 会直接 new DecorView() ,generateLayout() 会根据不同的 features 加载不同的布局文件添加给 DecorView,如果没有特别的设置就会加载 R.layout.screen_simple ,contentParent 就是这个id ID_ANDROID_CONTENT 对应的 View
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<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:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
到这里 Activity 的 setContentView() 执行完毕,整个 Activity 的 View 树创建完毕,但是光创建出这些 View 对象还不行,下面介绍这些 View 是何时执行测量和绘制的。