“This is the 29th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

The application Activity Launcher process (Life Cycle)

In the analysis of the Activity startup process in the previous chapter, the analysis of the Activity startup process will eventually enter the Activity life cycle process. In this process, there are mainly several steps (identification).

  1. A calls the preExecute function of ClientTransaction
  2. B Calls the execute function of the LaunchActivityItem object
  3. C calls the postExecute function of the LaunchActivityItem object
  4. D calls the TransactionExecutor cycleToPath function
  5. E Calls the execute function of the ResumeActivityItem object
  6. F calls the postExecute function of the ResumeActivityItem object

Let’s take a look at each of these steps

Call the preExecute function of the ClientTransaction object

Before we look at the code of this function, we need to know what arguments are passed into this function.

This function is called from the scheduleTransaction function of the ActivityThread object. ActivityThread does not override the scheduleTransaction function of its parent class ClientTransactionHandler. The parent function is called directly, so when this is passed in as an argument, you are passing an ActivityThread object

With its incoming parameters in mind, we move on to the ClientTransaction object’s preExecute function

public void preExecute(android.app.ClientTransactionHandler clientTransactionHandler) {
    if(mActivityCallbacks ! =null) {
        // mActivityCallbacks are initialized when their addCallback function is first called
        // We previously added a LaunchActivityItem object via addCallback, calling its preExecute function
        final int size = mActivityCallbacks.size();
        for (int i = 0; i < size; ++i) { mActivityCallbacks.get(i).preExecute(clientTransactionHandler, mActivityToken); }}if(mLifecycleStateRequest ! =null) {
        // Lifecycle Request is set to a ResumeActivityItem objectmLifecycleStateRequest.preExecute(clientTransactionHandler, mActivityToken); }}Copy the code

Therefore, in this function, the preExecute function of the previously initialized LaunchActivityItem object is called, followed by the preExecute function of the ResumeActivityItem object

LaunchActivityItem.java
public void preExecute(ClientTransactionHandler client, IBinder token) {
    // Add 1 to the mNumLaunchingActivities of the ActivityThread to indicate the Launch of the Activity
    client.countLaunchingActivities(1);
    client.updateProcessState(mProcState, false);
    client.updatePendingConfiguration(mCurConfig);
}

ResumeActivityItem.java
public void preExecute(ClientTransactionHandler client, IBinder token) {
    if (mUpdateProcState) {
        client.updateProcessState(mProcState, false); }}Copy the code

As you can see, the preloading process is mainly done in ActivityThread, and the detailed analysis is not covered here

The execute function of the LaunchActivityItem object

public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
    ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
            mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
            mPendingResults, mPendingNewIntents, mIsForward,
            mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
    client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
Copy the code

Based on the previous analysis, the client is essentially an ActivityThread object, so

ActivityThread.java
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {
    / /...
    final Activity a = performLaunchActivity(r, customIntent);
    / /...
    return a;
}

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r.activityInfo;
    / /...
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        // Get the ClassLoader object
        java.lang.ClassLoader cl = appContext.getClassLoader();
        // Call newActivity of Instrumentation to initialize the Activity object
        // We get the corresponding Class for the second argument, then initialize it, and we get an instance of the Activity subclass directly
        // Is also an instance of the main activity in the application
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        / /...
    }
    / /...

    try {
        // Get the Application object
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        / /...
        if(activity ! =null) {
            / /...
            // Call the attach function of the Activity object, which initializes the necessary information for the Activity object
            // For example, PhoneWindow initialization
            appContext.setOuterContext(activity);
            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);

            / /...
            // Set the Activity's theme
            int theme = r.activityInfo.getThemeResource();
            if(theme ! =0) {
                activity.setTheme(theme);
            }

            // Call callActivityOnCreate in Instrumentation,
            // In this function, the Activity's onCreate function is called
            activity.mCalled = false;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            / /...
        }
        // Note: The current ActivityClientRecord status is set to ON_CREATE
        r.setState(ON_CREATE);
        / /...
    }

    return activity;
}
Copy the code

And you can see that in this function,

  1. The attach function of the Activity is called first. This function is defined in activity.java and is final and therefore cannot be overridden by subclasses. It does some basic operations on the Activity, such as initializing and setting the PhoneWindow
  2. Second, call the callActivityOnCreate function in Instrumentation, which will eventually call actiivty. onCreate, the first function in the Activity lifecycle

PostExecute function for the LaunchActivityItem object

public void postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
    client.countLaunchingActivities(-1);
}
Copy the code

This function subtracts the value of mNumLaunchingActivities by 1 from the ActivityThread object to indicate that the Activity has started successfully

TransactionExecutor’s cycleToPath function

// lifecycleItem argument is a ResumeActivityItem object whose getTargetState function returns ON_RESUME
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */, transaction);

public static final int PRE_ON_CREATE = 0;
public static final int ON_CREATE = 1;
public static final int ON_START = 2;
public static final int ON_RESUME = 3;

private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState,
        ClientTransaction transaction) {
    // Remember that the state of ActivityClientRecord is set to ON_CREATE after the Activity onCreate function is called
    final int start = r.getLifecycleState();
    / /...
    // There is only ON_START between start and finish
    final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState);
    performLifecycleSequence(r, path, transaction);
}

private void performLifecycleSequence(ActivityClientRecord r, IntArray path, ClientTransaction transaction) {
    final int size = path.size();
    for (int i = 0, state; i < size; i++) {
        state = path.get(i);
        / /...
        switch (state) {
            case ON_START:
                // The handleStartActivity function of ActivityThread is called directly here
                mTransactionHandler.handleStartActivity(r.token, mPendingActions);
                break; }}public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) {
    final ActivityClientRecord r = mActivities.get(token);
    final Activity activity = r.activity;
    / /...
    // Start
    // Calling the Activity's performStart function will eventually call the Activity's onStart function
    activity.performStart("handleStartActivity");
    r.setState(ON_START);
    / /...
    // Restore instance state
    // Finally call the Activity's onRestoreInstanceState function
    if (pendingActions.shouldRestoreInstanceState()) {
        if (r.isPersistable()) {
            if(r.state ! =null|| r.persistentState ! =null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, r.persistentState); }}else if(r.state ! =null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); }}// Call postOnCreate()
    // Finally call the Activity's onPostCreate function
    if (pendingActions.shouldCallOnPostCreate()) {
        activity.mCalled = false;
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnPostCreate(activity, r.state,
                    r.persistentState);
        } else {
            mInstrumentation.callActivityOnPostCreate(activity, r.state);
        }
        / /...}}Copy the code

The onStart, onRestoreInstanceState, and onPostCreate functions are called here in sequence, as shown in the code and remarks above

The execute function of the ResumeActivityItem object

public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
    Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
    client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
            "RESUME_ACTIVITY");
    Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
Copy the code

According to the above analysis, the ActivityThread’s handleResumeActivity function will eventually call the Activity’s onResume function

The postExecute function for the ResumeActivityItem object

public void postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {
    / /...
    // TODO(lifecycler): Use interface callback instead of AMS.
    ActivityTaskManager.getService().activityResumed(token);
    / /...
}
Copy the code

As you can see, the Activity onResume function is reported to the ATMS

conclusion

Based on the previous three articles, the general process of launching an application Activity Launcher has been combed out. The code sequence diagram of the whole process is as follows