Where is onCreate() called

To know where onCreate() is called, first look at where the Activity is created. Start by looking for the app’s main() method, in the ActivityThread class

public static void main(String[] args) { ... ActivityThread thread = new ActivityThread(); . }Copy the code

The ActivityThread class is created in the main() method, so let’s look again at the handleLaunchActivity() method of the ActivityThread class

@Override public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) { ... final Activity a = performLaunchActivity(r, customIntent); . }Copy the code

On line 3409, we see that calling performLaunchActivity() in handleLaunchActivity() returns an Activity, and we have created our Activity object. So where does onCreate() get called, let’s go to performLaunchActivity(), and there’s this line at line 3183

activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
Copy the code

The creation of the Activity is assigned to the Instrumentation class, continuing on line 3243

if (r.isPersistable()) {
	mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
	mInstrumentation.callActivityOnCreate(activity, r.state);
}
Copy the code

MInstrumentation. CallActivityOnCreate () in this way will be to call the Activity’s onCreate (), to the Activity’s onCreate () is invoked. Of course, we can also look at some other methods of Activity: handleStartActivity() calls onStart(), and handleResumeActivity calls onResume().

What does setContentView() do

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
Copy the code

SetContentView () will then execute setContentVeiw() to the AppCompatDelegateImpl class

@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();
}
Copy the code

This is a familiar line of code, find a contentParent by findViewById and instantiate our layout file as View through inflate() and add it to the contentParent, At this point, all the views of our Activity are instantiated, but creating objects is useless because the layout and measurement of the views have not yet occurred, so we cannot directly get the width and height of a View in onCreate().

What is the mSubDecor layout structure like

Let’s take a look at the mSubDecor layout before we look at the Activity drawing process. Open the ensureSubDecor ()

private void ensureSubDecor() { ... mSubDecor = createSubDecor(); . }Copy the code

Take a look at 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; }Copy the code

First, the subDecor will cause different layouts according to different configurations. Normally, our Activity loads the r.layout. abc_screen_simple layout. Open the SDK to find the layout file

<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 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>Copy the code

Contentview.setid (Android.r.D.C ontent) replaces action_bar_activity_content with R.D.C ontent, So above we will add the layout passed in by setContentView(resId) to the ContentFrameLayout, mSubDecor is the FitWindowsLinearLayout.

What is the mWindow implementation class and where is it initialized

SetContentView (subDecor) is called after the subDecor is created, where the mWindow was created. Let’s look at 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; }Copy the code

In attachToWindow(), mWindow is assigned, and ensureWindow calls the Activity’s getWindow(), which returns the Activity’s member variable mWindow. Go back to where the onCreate method was called above, in the performLaunchActivity() method

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; }Copy the code

The Activity is first initialized by calling Attach () after it is created

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(); . }Copy the code

So you can see here that mWindow is a PhoneWindow object, setContentView()

public void setContentView(View view, ViewGroup.LayoutParams params) { if (mContentParent == null) { installDecor(); }... mContentParent.addView(view, params); . }Copy the code

This will add the subDecor created above to mContentParent. Now look where mContentParent is initialized. Open the installDecor() method

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;
}
Copy the code

GenerateDecor () directly new DecorView(),generateLayout() loads different layout files to add to the DecorView according to different features. Screen_simple. ContentParent is the View corresponding to this ID ID_ANDROID_CONTENT

<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>
Copy the code

At this point the Activity’s setContentView() is finished, and the entire Activity’s View tree has been created, but it’s not enough to just create the View objects. Here’s how these views measure and draw.