preface

In the Android Activity creation process above, we talked about the ActivityThread creating an Activity. There is no reference to Activity lifecycle flow. This article starts Activity B with Activity A, and then returns the jump logic of Activity A through Finish to see the flow of Activity’s life cycle through AMS. Before reading this article, you should have some knowledge of the Activity startup process, AMS, and Android interprocess communication. Reading ahead is recommended

  • Multi-process and cross-process communication in Android
  • Essentials of the Android system startup process
  • The Android Activity creation process

To begin, here’s the official simplified lifecycle diagram:

At the same time, put the lifecycle flow mode under the startup logic in this paper:

  • A Start B: A:onPause->B:onCreate->B:onStart->B:onResume->A:onStop
  • A: B:onPause->A:onRestart->A:onStart->A:onResume->B:onStop->B:onDestroy

Next we follow the A. startActivity method to start B source code to see the Activity lifecycle flow process.

Lifecycle flow during Activity startup (A->B)

When an Activity calls the startActivity(Intent(this,B::class.java)) method, the main flow is described in the Android Activity creation process. This time, we start directly with the lifecycle flow. Also is when startActivity call go get ActivityStack resumeTopActivityInnerLocked through layer upon layer. This method is also explained in the Android Activity creation process. We also mentioned in that article that this calls the Activity’s onPause method. Let’s examine its call logic:

The onPause call logic of an Activity

The key codes are as follows:

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false); if (mResumedActivity ! = null) { pausing |= startPausingLocked(userLeaving, false, next, false); } / /... } final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, boolean pauseImmediately) { ActivityRecord prev = mResumedActivity; mPausingActivity = prev; If (prev.attachedToProcess()) {try { mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); } catch (Exception e) {} } }Copy the code

Before the Activity starts, the startPausingLocked method is called to make the current Activity enter the onPause state. The key is: mService. GetLifecycleManager (). ScheduleTransaction. So let’s focus on this.

Among these is mService ActivityTaskManagerService instance, getLifecycleManager () returns the ClientLifecycleManager scheduleTransaction method code is as follows:

void scheduleTransaction(@NonNull IApplicationThread client, @NonNull IBinder activityToken, @NonNull ActivityLifecycleItem stateRequest) throws RemoteException { final ClientTransaction clientTransaction = transactionWithState(client, activityToken, stateRequest); scheduleTransaction(clientTransaction); } private static ClientTransaction transactionWithState(@NonNull IApplicationThread client, @nonnull IBinder activityToken, @nonnull ActivityLifecycleItem stateRequest) { And set its mLifecycleStateRequest to stateRequest // that is, the PauseActivityItem instance final ClientTransaction ClientTransaction = ClientTransaction.obtain(client, activityToken); clientTransaction.setLifecycleStateRequest(stateRequest); return clientTransaction; } void scheduleTransaction(ClientTransaction transaction) throws RemoteException { final IApplicationThread client = transaction.getClient(); transaction.schedule(); if (! (client instanceof Binder)) { transaction.recycle(); }}Copy the code

The code is not complex and calls ClientTransaction’s Schedule method through an overload.

private IApplicationThread mClient;

public void schedule() throws RemoteException {
        mClient.scheduleTransaction(this);
 }
Copy the code

The code is simpler, where mClient is the client instance of IApplicationThread, which is itself an AIDL and is implemented as an inner class in ActivityThread. Here’s how AMS uses AIDL (how AIDL works) to communicate with ActivityThread. As you can see, AMS, as the server, sends the entire ClientTransaction to the ActivityThread via scheduleTransaction. The scheduleTransaction implementation in ActivityThread is as follows:

@Override
 public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
      ActivityThread.this.scheduleTransaction(transaction);
}

Copy the code

The scheduleTransaction method of ActivityThread is called, which is implemented in its parent class ClientTransactionHandler:

 void scheduleTransaction(ClientTransaction transaction) {
        transaction.preExecute(this);
        sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code

The sendMessage method is called using the inner class H in ActivityThread, which is a Handler message loop mechanism. Because the messages received by the Binder server run in the Binder thread pool, this is switched to the main thread first. Perform subsequent operations. The ActivityThread sendMessage method has a lot of overloading, so we won’t expand it and just look at how it handles messages:

case EXECUTE_TRANSACTION:
        final ClientTransaction transaction = (ClientTransaction) msg.obj;
        mTransactionExecutor.execute(transaction);
        if (isSystem()) {
		 transaction.recycle();
	  }
break;
Copy the code

TransactionExecutor’s execute method is called:

public void execute(ClientTransaction transaction) { //.. executeCallbacks(transaction); executeLifecycleState(transaction); } public void executeCallbacks(ClientTransaction transaction) { final int lastCallbackRequestingState = lastCallbackRequestingStafinal List<ClientTransactionItem> callbacks = transaction.getCallbacks(); final int size = callbacks.size(); for (int i = 0; i < size; ++i) { //.. item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); / /.. if (postExecutionState ! = UNDEFINED && r ! = null) { // Skip the very last transition and perform it by explicit state request instead. final boolean shouldExcludeLastTransition = i == lastCallbackRequestingState && finalState == postExecutionState; cycleToPath(r, postExecutionState, shouldExcludeLastTransition, transaction); } } } private void executeLifecycleState(ClientTransaction transaction) { final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest(); / /.. lifecycleItem.execute(mTransactionHandler, token, mPendingActions); lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions); }Copy the code

The two member variables in ClientTransaction are implemented as follows:

 private List<ClientTransactionItem> mActivityCallbacks;
 private ActivityLifecycleItem mLifecycleStateRequest;
Copy the code

As you can see from the code above, the main purpose of **TransactionExecutor’s execute is to call ClientTransactionItem’s Execute and ActivityLifecycleItem’s execute methods. All of ClientTransaction’s Callbacks and lifecycleStateRequest(ActivityLifecycl) are called in turn through the executeCallbacks and executeLifecycleState methods EItem). ** What are ClientTransactionItem and ActivityLifecycleItem?

Remember the PauseActivityItem above? Its inheritance relationship is as follows:

** essentially inherits from BaseClientRequest and is used to drive Activity lifecycle calls. ClientTransaction may have multiple implementations of BaseClientRequest stored in mActivityCallbacks and mLifecycleStateRequest. The execute method essentially executes, in turn, the methods defined by the BaseClientRequest implementation of these classes. ** We will not expand the cycleToPath method here until we encounter it later.

Execute (PauseActivityItem);

public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
        client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,
                "PAUSE_ACTIVITY_ITEM");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
Copy the code

The client is our ActivityThread here that it inherited from ClientTransactionHandler, client. HandlePauseActivity method is as follows:

@Override public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, String reason) { ActivityClientRecord r = mActivities.get(token); if (r ! = null) { performPauseActivity(r, finished, reason, pendingActions); / /.. } } private Bundle performPauseActivity(ActivityClientRecord r, boolean finished, String reason, PendingTransactionActions pendingActions) { //.. performPauseActivityIfNeeded(r, reason); / /.. } private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) { //.. mInstrumentation.callActivityOnPause(r.activity); / /.. }Copy the code

The code is very simple, calling the Instrumentation callActivityOnPause:

public void callActivityOnPause(Activity activity) {
        activity.performPause();
    }
Copy the code

Then call the Activity’s performPause:

final void performPause() { dispatchActivityPrePaused(); mDoReportFullyDrawn = false; mFragments.dispatchPause(); mCalled = false; onPause(); writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause"); mResumed = false; if (! mCalled && getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.GINGERBREAD) { throw new SuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onPause()"); } dispatchActivityPostPaused(); }Copy the code

This is obviously the onPause method of the Activity.

That’s not all. BaseClientRequest defines three methods: preExecute, execute, and postExecute. Based on their names, it is not hard to see what the three methods do and in what order they are executed. Let’s focus on the latter two methods: Execute and postExecute. Each time they are executed in sequence, let’s look at what the postExecute of the PauseActivityItem does:

public void postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { if (mDontReport) { return; } try { // TODO(lifecycler): Use interface callback instead of AMS. ActivityTaskManager.getService().activityPaused(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }}Copy the code

Call the AMS (here is the corresponding ActivityTaskManagerService) activityPaused method, of course, also by AIDL methods, is not known to the AIDL can see Android in the way of multi-process and cross-process communication. ActivityPaused is implemented as follows:

public final void activityPaused(IBinder token) { final long origId = Binder.clearCallingIdentity(); synchronized (mGlobalLock) { ActivityStack stack = ActivityRecord.getStackLocked(token); if (stack ! = null) { stack.activityPausedLocked(token, false); } } Binder.restoreCallingIdentity(origId); }Copy the code

The key is that ActivityStack’s activityPausedLocked methods are called with the following logic:

final void activityPausedLocked(IBinder token, boolean timeout) { final ActivityRecord r = isInStackLocked(token); if (r ! = null) { mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); // Note that mPausingActivity is already marked in startPausingLocked above, If (mPausingActivity == r) {//... try { completePauseLocked(true /* resumeNext */, null /* resumingActivity */); } finally { mService.mWindowManager.continueSurfaceLayout(); } return; } / /.. } mRootActivityContainer.ensureActivitiesVisible(null, 0, ! PRESERVE_WINDOWS); } private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) { ActivityRecord prev = mPausingActivity; if (prev ! = null) { //.. addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */, "completePauseLocked"); / /.. } mPausingActivity = null; } private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed, String reason) { if (! mStackSupervisor.mStoppingActivities.contains(r)) { //.. mStackSupervisor.mStoppingActivities.add(r); } / /.. }Copy the code

The logic is clear. After an ActivityThread calls the Activity’s onPause method, the ActivityThread tells AMS, AMS then adds the Activity to the mStoppingActivities of ActivityStackSupervisor: ** Where mStoppingActivities is an ArrayList that stores information about activities marked as needing to call the onStop method. This is critical because AMS uses mStoppingActivities to determine which activities need to call onStop after a newly started Activity is displayed. ** The mFinishingActivities member variable in ActivityStackSupervisor is also used for this purpose, except that it stores information about the Activity that needs to be destroyed.

At this point, an Activity has already been called to the onPasue method. Before we look at the flow of B activities, let’s take a look at ActivityLifecycleItem, which has several implementations in the system:

  • PauseActivityItem;
  • StartActivityItem;
  • ResumeActivityItem;
  • StopActivityItem;
  • DestroyActivityItem
  • LaunchActivityItem
  • .

I believe that seeing these naming rules, you must know their role. Yes, these names correspond to the Activity lifecycle. As you can see from PauseActivityItem, AMS uses these classes to manage the Activity lifecycle. Of course, this is managed using AIDL, cross-process communication with ActivityThreads and Instrumentation. But they don’t correspond exactly to the Activity life cycle, reStart is true. Because it is driven by other life cycles.

So far, I’ve covered the key to the ActivityLifecycleItem, which is how AMS manages the life cycle. Instead of describing their invocation flow, we’ll look directly at their implementation, which is the preExecute, Execute, and postExecute methods.

The next step is the invoke logic for the Activity B that is started

B Activity onCreate, onStart, and onResume

At the end of the Android Activity creation process, which is the performLaunchActivity method of the ActivityThread, note that the call chain for this method comes from the Execute method of the LaunchActivityItem. I won’t expand on the detailed code.

The code for performLaunchActivity is as follows:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ActivityInfo aInfo = r.activityInfo; / /.. Activity activity = null; try { java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); / /.. } / /.. try { //.. if (activity ! = null) { CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); / /.. 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

This code does three things: create an Activity instance through reflection, call the Attach method for the Activity, and call the callActivityOnCreate method for Instrumentation, which is overloaded but ultimately implements:

public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);
        postPerformCreate(activity);
}
Copy the code

The main purpose is to call the Activity’s performCreate method:

final void performCreate(Bundle icicle, PersistableBundle persistentState) { //.. if (persistentState ! = null) { onCreate(icicle, persistentState); } else { onCreate(icicle); } / /.. }Copy the code

Finally, the Activity’s onCreate method is called. OnStart and onResume should come next.

Remember the previous TransactionExecutor. CycleToPath method has yet to explain? Take a look at its implementation:

private void cycleToPath(ActivityClientRecord r, int finish, boolean excludeLastState, ClientTransaction transaction) { final int start = r.getLifecycleState(); 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); if (DEBUG_RESOLVER) { Slog.d(TAG, tId(transaction) + "Transitioning activity: " + getShortActivityName(r.token, mTransactionHandler) + " to state: " + getStateName(state)); } switch (state) { case ON_CREATE: mTransactionHandler.handleLaunchActivity(r, mPendingActions, null /* customIntent */); break; case ON_START: mTransactionHandler.handleStartActivity(r, mPendingActions); break; case ON_RESUME: mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */, r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: mTransactionHandler.handlePauseActivity(r.token, false /* finished */, false /* userLeaving */, 0 /* configChanges */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: mTransactionHandler.handleStopActivity(r.token, false /* show */, 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "performLifecycleSequence. cycling to:" + path.get(size - 1)); break; case ON_RESTART: mTransactionHandler.performRestartActivity(r.token, false /* start */); break; default: throw new IllegalArgumentException("Unexpected lifecycle state: " + state); }}}Copy the code

Among them: The getLifecyclePath() method calculates the intermediate lifecycle path based onStart and finish. As you can see from our code flow, this path is only onStart, Also is the final call mTransactionHandler. HandleStartActivity (r, mPendingActions); :

public void handleStartActivity(ActivityClientRecord r, PendingTransactionActions pendingActions) { // // Start activity.performStart("handleStartActivity"); / /.. } } final void performStart(String reason) { //.. mInstrumentation.callActivityOnStart(this); }Copy the code

In the end, or call Instrumentation. CallActivityOnStart method, will not expand the method, direct call inside the onStart method of the Activity.

In this case, we need to look again at the realStartActivityLocked method in ActivityStackSupervisor:

boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc, boolean andResume, boolean checkConfig) throws RemoteException { final ClientTransaction clientTransaction = ClientTransaction.obtain( proc.getThread(), r.appToken); clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent), System.identityHashCode(r), r.info, // TODO: Have this take the merged configuration instead of separate global // and override configs. mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(), r.icicle, r.persistentState, results, newIntents, dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(), r.assistToken)); / / start andResume came here to true if (andResume) {lifecycleItem = ResumeActivityItem. Obtain (dc) isNextTransitionForward ()); } else { lifecycleItem = PauseActivityItem.obtain(); } clientTransaction.setLifecycleStateRequest(lifecycleItem); }Copy the code

The code created with ClientTransaction is shown above. You can see: The mLifecycleStateRequest parameter is set to ResumeActivityItem. After executing the ClientTransaction callBaclk, After the Execute method on LaunchActivityItem. The execute method of mLifecycleStateRequest is then executed. Which is the execute method for ResumeActivityItem:

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

Call the ActivityThread side method is AIDL across processes, tracking client. HandleResumeActivity method:

public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) { //.. Final ActivityClientRecord r = performResumeActivity(Token, finalStateRequest, Reason); / /.. Looper.myqueue ().addidleHandler (new Idler()); }Copy the code

The call logic is the same as in the onPause flow above: ActivityThread-> Instrumentation->Activity. Finally execute activity.performResume


final void performResume(boolean followedByPause, String reason) {
        
        performRestart(true /* start */, reason);

        //..

        mInstrumentation.callActivityOnResume(this);
        //..
}

final void performRestart(boolean start, String reason) {
        

    if (mStopped) {
        mStopped = false;
        mInstrumentation.callActivityOnRestart(this);
        
        if (start) {
            performStart(reason);
        }
    }
}
Copy the code

Code logic is very simple, first performRestart method, if the Activity is in the stop state, calls onRestart method, already this call onStart method, and then call Instrumentation. CallActivityOnResume method. So here we have our newly created Activity, and now we’re in the start state and we’re just going to go through the callActivityOnResume process. The onResume method of the Activity is finally called through Instrumentation.

At this point, the onResume method of the newly launched B Activity has been called. Next comes the onStop method of an Activity.

The onStop method of an Activity

Looper.myqueue ().addidleHandler (new Idler()); . This is an IdleHandler. The final call logic is:

private class Idler implements MessageQueue.IdleHandler { @Override public final boolean queueIdle() { ActivityClientRecord a = mNewActivities; / /.. if (a ! = null) { IActivityTaskManager am = ActivityTaskManager.getService(); ActivityClientRecord prev; do { if (a.activity ! = null && ! a.activity.mFinished) { try { am.activityIdle(a.token, a.createdConfig, stopProfiling); a.createdConfig = null; } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } } while (a ! = null); } / /.. }}Copy the code

The whole logic is when our B Activity in the idle state, and through the AIDL, calls the ActivityTaskManagerServer activityIdle method:

public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
        final long origId = Binder.clearCallingIdentity();
        try {
                //
                final ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token,
                        false /* fromTimeout */, false /* processPausingActivities */, config);
               //..
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
}
Copy the code

Then look at ActivityStackSuperVisor activityIdleInternalLocked method:

final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout, boolean processPausingActivities, Configuration config) { ActivityRecord r = ActivityRecord.forTokenLocked(token); if (r ! = null) {/ / find all need to stop the Activity of the final ArrayList < ActivityRecord > stops = processStoppingActivitiesLocked (r, true /* remove */, processPausingActivities); NS = stops ! = null ? stops.size() : 0; for (int i = 0; i < NS; i++) { r = stops.get(i); final ActivityStack stack = r.getActivityStack(); if (stack ! = null) {if (r.f inishing) {/ / if the Activity is marked as need to finish the stack. The finishCurrentActivityLocked (r, ActivityStack.FINISH_IMMEDIATELY, false, "activityIdleInternalLocked"); } else { stack.stopActivityLocked(r); }}} / /.. return r; } final ArrayList<ActivityRecord> processStoppingActivitiesLocked(ActivityRecord idleActivity, boolean remove, boolean processPausingActivities) { ArrayList<ActivityRecord> stops = null; for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) { ActivityRecord s = mStoppingActivities.get(activityNdx); if (remove) { final ActivityStack stack = s.getActivityStack(); final boolean shouldSleepOrShutDown = stack ! = null ? stack.shouldSleepOrShutDownActivities() : mService.isSleepingOrShuttingDownLocked(); if (! animating || shouldSleepOrShutDown) { stops.add(s); mStoppingActivities.remove(activityNdx); } } } return stops; }Copy the code

The key code is shown above, and the workflow is roughly as follows: First, find all activities that need to be stopped by looking in the member variable mStoppingActivities. This is what we added to an Activity by addToStopping when we called onPause. And at this point, our Activity is not marked as finish, so eventually the invocation of the logic is: ActivityStack. StopActivityLocked

final void stopActivityLocked(ActivityRecord r) { //.. if (r.attachedToProcess()) { try { mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken, StopActivityItem.obtain(r.visible, r.configChangeFlags)); }}Copy the code

Once the StopActivityItem is found, the problem is simple: look at its execute method:

public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
        client.handleStopActivity(token, mShowWindow, mConfigChanges, pendingActions,
                true /* finalStateRequest */, "STOP_ACTIVITY_ITEM");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
Copy the code

Trace the handleStopActivity method on ActivityThread: ActivityThread.handleStopActivity->ActivityThread.performStopActivityInner->ActivityThread.callActivityOnStop->Activity. performStop->Instrumentation.callActivityOnStop:

public void callActivityOnStop(Activity activity) {
        activity.onStop();
}
Copy the code

Finally, the Activity’s onStop method is called.

Lifecycle flow in the Activity return process (B->A)

After B calls the Finish method, the method flow is as follows: Activity.finish->ActivityTaskManagerService.finishActivity->ActivityStack.requestFinishActivityLocked->ActivityStack.sta RtPausingLocked. So what’s going to start right away is A’s onPause method

B The onPause call logic of the Activity

See ActivityStack. StartPausingLocked code:

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, boolean pauseImmediately) { if (prev.attachedToProcess()) { if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev); try { EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev), prev.shortComponentName, "userLeaving=" + userLeaving); mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(), prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); }}Copy the code

(PauseActivityItem) (PauseActivityItem) (PauseActivityItem) (PauseActivityItem) (PauseActivityItem) Execute with the Execute method on the PauseActivityItem, which I won’t describe here.

An Activity’s onRestart, onStart, and onResume

Here, the postExecute method on PauseActivityItem comes in handy:

public void postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { if (mDontReport) { return; } try { ActivityTaskManager.getService().activityPaused(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }}Copy the code

The call logic is as follows: ActivityTaskManagerService. ActivityPaused – > ActivityStack. ActivityPausedLocked pletePauseLocked – > ActivityStack.com and so on. Here after a pile of code calls, eventually go process with the Activity to create similar – came to resumeTopActivityInnerLocked method. During this time, AMS also does several things, including adding the description of B Activity to mFinishingActivities and finding an Activity to resume. The next is called resumeTopActivityInnerLocked. Instead of launching the product, resume the product:

final ClientTransaction transaction =
    ClientTransaction.obtain(next.app.getThread(), next.appToken);
transaction.setLifecycleStateRequest(
                ResumeActivityItem.obtain(next.app.getReportedProcState(),
                        getDisplay().mDisplayContent.isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
Copy the code

Instead of describing the code call flow, I’ll show you the key code. As you can see, ResumeActivityItem again. The onResume method is called by ResumeActivityItem’s execute method, and then the Activity’s performResume method. In the above article, we have analyzed this method. It first calls the performRestart method, and then call the Instrumentation. CallActivityOnResume method, The Instrumentation. CallActivityOnResume method is onResume process. This is where the performRestart method comes in handy. The current Activity is marked stop. Therefore, the following process will be followed:

final void performRestart(boolean start, String reason) { if (mStopped) { //.. mInstrumentation.callActivityOnRestart(this); writeEventLog(LOG_AM_ON_RESTART_CALLED, reason); if (! mCalled) { throw new SuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onRestart()"); } if (start) { performStart(reason); }}}Copy the code

At this point, mStopped has the value true. Start also passes true. As you can see, this is where the onRestart and onStart methods are executed.

B Activity onStop and onDestory

After A Resume, looper.myQueue ().addidleHandler (new Idler()); Call to ActivityStackSuperVisor activityIdleInternalLocked method. At this point, the code calls a different logic:

final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout, boolean processPausingActivities, Configuration config) { ArrayList<ActivityRecord> finishes = null; final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r, true /* remove */, processPausingActivities);  NS = stops ! = null ? stops.size() : 0; if ((NF = mFinishingActivities.size()) > 0) { finishes = new ArrayList<>(mFinishingActivities); mFinishingActivities.clear(); } for (int i = 0; i < NF; i++) { r = finishes.get(i); final ActivityStack stack = r.getActivityStack(); if (stack ! = null) { activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle"); }}}Copy the code

Since B Activity is already added to mFinishingActivities when finish() is called, This time you’ll go to ActivityStack’s destroyActivityLocked method. The logic turns out to be as follows:

final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) { try{ mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken, DestroyActivityItem.obtain(r.finishing, r.configChangeFlags)); }}Copy the code

DestroyActivityItem appears. Then the problem is simple, just look at its execute method:

public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); client.handleDestroyActivity(token, mFinished, mConfigChanges, false /* getNonConfigInstance */, "DestroyActivityItem");  Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); }Copy the code

Following the old discussion, handleDestroyActivity->performDestroyActivity in ActivityThread:

ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance, String reason) {
    if (!r.stopped) {
        callActivityOnStop(r, false /* saveState */, "destroy");
    }

    try{
        mInstrumentation.callActivityOnDestroy(r.activity);
    }
}

private void callActivityOnStop(ActivityClientRecord r, boolean saveState, String reason) {

        try {
            r.activity.performStop(r.mPreserveWindow, reason);
        } 
}
Copy the code

Since B Activity is in onPause state, the code will first execute the callActivityOnStop method, where Activity. PerformStop calls the callActivityOnStop method in Instrumentation. CallActivityOnStop and callActivityOnDestroy are implemented as follows:

public void callActivityOnStop(Activity activity) {
        activity.onStop();
}

public void callActivityOnDestroy(Activity activity) {
      activity.performDestroy();
}
Copy the code

The logic is clear, calling onStop and onDestroy in succession (activity.performDestroy is simple, so I won’t post it)

conclusion

At this point, the invoke logic for the Activity life cycle is complete. And we can see, The lifecycle is driven by TransactionExecutor fetching the ActivityLifecycleItem and ClientTransactionItem from ClientTransaction and then executing their execute and other methods. . It involves the communication between the AMS process and the App process, mainly achieved by AMS and ActivitThread, and also involves the knowledge of IdleHandler and other handlers.

The general call logic is as follows:

The general steps are as follows:

  • AMS passes the concrete implementation of BaseClientRequest (which controls the Activity lifecycle flow, depending on the implementation) to ActivityThread.
  • Once the ActivityThread gets the BaseClientRequest implementation, it switches to the main thread and executes its implementation (preExecute, Execute, and postExecute).
  • Different implementations of BaseClientRequest call different methods of ActivityThread, and then the ActivityThread implements the Activity lifecycle control through Instrumentation.
  • Finally, the results are returned to AMS

AMS and ActivityThread are in a different process, so AIDL is used to communicate with each other, while ActivityThread first switches threads through Handler to perform subsequent operations. The results are eventually returned to AMS using AIDL again.

If you don’t understand any of the concepts mentioned in the article. You can refer to the article:

  • Handler
  • Android multi-process and process communication
  • Android startup process
  • The Android Activity startup process

Reading in order is recommended