“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).
- A calls the preExecute function of ClientTransaction
- B Calls the execute function of the LaunchActivityItem object
- C calls the postExecute function of the LaunchActivityItem object
- D calls the TransactionExecutor cycleToPath function
- E Calls the execute function of the ResumeActivityItem object
- 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,
- 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
- 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