Activity
management
Activity is the most complex component, responsible for displaying the UI and handling various input events. Activity provides Windows in which to draw interfaces, as well as a variety of controls for easy development. The Activity official website portal
In addition, Android does not provide external interface to start the process, only when the Activity or Service is started, the system starts the process as required.
Activity
Life cycle of
aboutActivity
Let’s take a look at the official illustration:
The life cycle diagram of an Activity implies three states when an Activity is running, which are:
- Active state: newly started
Activity
Located at the very front of the screen, it accepts state input from the user - Pause state: when
Activity
Being a transparent or translucentActivity
Overlay, at this pointActivity
Although it cannot accept user input, it is still visible - Stop state: when a
Activity
Totally by anotherActivity
Overwrite, cannot accept user input and is not visible
When the state of an Activity object changes, it calls the abstract interface defined in the figure above to notify the application. Related descriptions are as follows:
onCreate()
: whenActivity
Called when the object is createdonStart()
: whenActivity
inFramework
Called when the data structure inonResume()
: whenActivity
Called when it reaches the top of the stack and becomes activeonPause()
: whenActivity
When switching from the front end of the stack to the back end, the method is paused and calledonStop()
: whenActivity
Called when it is completely invisibleonDestroy()
: in the destruction ofActivity
Before, the system invokes this method first
Intents, Tasks, LaunchMode, etc. (Intent, Task, LaunchMode
Intent
,Task
withLaunchMode
understandIntent
An Intent is an abstract description of an action that is requested to be performed. It is usually used as a parameter to complete the messaging between components. For more detailed postures, please refer to the official website description: official portal
The Intent class is defined as follows:
public class Intent implements Parcelable.Cloneable {
private String mAction;
private Uri mData;
private String mType;
private String mPackage;
private ComponentName mComponent;
private int mFlags;
private ArraySet<String> mCategories;
private Bundle mExtras;
private Rect mSourceBounds;
private Intent mSelector;
private ClipData mClipData;
}
Copy the code
The common parameter meanings are as follows:
mAction
Is a string specifying what operation to perform.- in
Intent
Class defines a large number ofAction
, e.g.ACTION_VIEW
,ACTION_SEND
And so on. - these
Action
The function of is related to specific functional modules and expresses the intention to be implemented
- in
mData
Store data that needs to be passed, of typeURI
.URI
Is the Uniform Resource Identifier (Uniform Resources Identifier
Short for)- Originally used to denote
Web
Resources such as HTML documents, images, files, etc URL(Uniform Resource Locator)
isURI
A kind of
mType
isMIME
Format string representing the data type.MIME
Is a multifunctionalInternet
Mail Extension Service (Multipurpose Internet Mail Extensions
The abbreviation of)- The earliest English email system, later applied to the browser. Format for example:
text/plain``application/x-gzip
Etc. - Normally this data type does not need to be specified and can be sped up if this field is set
Intent
Matching speed of
mComponent
Used to specify receivingIntent
Is the name of the target componentmComponent
Is of typeComponentName
, it contains two strings:mPackage
andmClass
, the former is used to specify the package name and the latter is used to specify the class nameIntent
If is definedmComponent
theIntent
Will be sent directly to the specified component and will not be looked up through other property combinations
mFlags
It’s called the logo, in theIntent
There are many definitions in the classflag
Relative constants of. There are two main types- In order to
FLAG_ACTIVITY_...
At the beginning, for controlActivity
Parameters related to startup, such asFLAG_ACTIVITY_NEW_TASK
- In order to
FLAG_RECEIVER_...
The parameter used to broadcast
- In order to
mCategories
A contain should be handledIntent
A string of additional information about the component type. There are two common categories:CATEGORY_BROWSABLE
Goal:Activity
Allows itself to be launched through a web browser to display the data referenced by the linkCATEGORY_LAUNCHER
: theActivity
Is the beginning of the taskActivity
- You can put any number of category descriptions into one
Intent
In, but mostlyIntent
No category is required
mExtras
Represents a collection of all additional information.mExtras
The data type isBundle
- You can use a variety of
putExtra()
Method to addExtra data
, each method accepts two parameters:key
andvalue
Task
A Task is a collection of activities. Android stores the activities used by the user during a related operation in Task in sequence, so that when the back key is pressed, it can be rolled back in reverse order.
Tasks manage activities in a last-in, first-out manner, like a stack. When you press recent, a selection list pops up. This list is a collection of existing tasks in the system. Selecting a Task brings the Activity as a whole to the foreground. The order of activities in a Task usually cannot be changed, but can only be added or removed from the stack.
AMS uses ActivityStack to manage tasks. The tasks managed by ActivityStack are stored in the member variable mTaskHistory, as defined below:
class ActivityStack{
private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
}
Copy the code
MTaskHistory is a list of TaskRecord objects. The TaskRecord object represents a Task, and its member variable mActivities is also a list of all ActivityRecord objects in that Task. MActivities are defined as follows:
class TaskRecord{
final ArrayList<ActivityRecord> mActivities;
}
Copy the code
So how do you start a new oneTask
?
Intent
A flag is defined inFLAG_ACTIVITY_NEW_TASK
In thestartActivity()
theIntent
Adding this flag to the parameter opens a new oneTask
- But if the system already has the same
affinity
theTask
It exists. It doesn’t start another oneTask
, but will be the oldTask
To the front desk
So,affinity
Where is it defined?
affinity
It means affinity, is through<activity>
Of the labelandroid:taskAffinity
Property- When using flags
FLAG_ACTIVITY_NEW_TASK
Start aActivity
When theActivity
thetaskAffinity
The string in the property becomesTask
theaffinity
- I’ll add this later
Task
theActivity
Even theirtaskAffinity
Property defines a different string and does not changeTask
The existingaffinity
- if
<activity>
Not specified in the tagandroid:taskAffinity
Property, this oneActivity
Will inherit<application>
Of the labelandroid:taskAffinity
attribute - if
<application>
Of the labelandroid:taskAffinity
Property is also undefined and the application package name will be used as the default value- Because of this, if you start another application in your application
Activity
Even if usedFLAG_ACTIVITY_NEW_TASK
The logo also does not necessarily launch a new oneTask
- Unless the
Activity
It’s defined differentlytaskAffinity
attribute
- Because of this, if you start another application in your application
LaunchMode
The startup mode of an Activity implies the reuse of Activity objects. The official portal is also described in detail on the official website of the startup mode
When you start aActivity
When, if the system backgroundTask
There is already one of theActivity
The instance exists and the system is created with a new oneActivity
Or will it already existActivity
Switch to the foreground?
The answer is both. There are a number of factors that can affect the outcome. This includes Activity property values and flags specified in the Intent
Let’s take a look at the impact of the Activity attribute launchMode:
standard
Mode: Default.standard
Mode ofActivity
This is created on each startupActivity
Instance object of- The same
Task
Can exist simultaneously inActivity
Multiple instances of - a
Activity
Multiple instances of can appear in multipleTask
The stack
singleTop
model- If the target
Task
The top of the existingActivity
Instance, the system will call the instanceonNewIntent()
Method to itIntent
Instead of creating a new oneActivity
Instance. - If it’s not at the top of the stack, this
standard
Create a new instance object as usual
- If the target
singleTask
model- Set up the
singleTask
Patterns ofActivity
It is system unique and can only be created in the systemActivity
An instance object of - Boot set to
singleTask
Patterns ofActivity
If this parameter already exists in the systemActivity
The instance object of theTask
The one in front of itActivity
All pop-ups on the stack will beActivity
Bring it to the top of the stack and call itonNewIntent()
Method pass newIntent
object - If it does not exist in the system
Activity
Will create an instance object ofActivity
Instance object of- If the
Activity
thetaskAffinity
Property value and currentTask
theaffinity
If the value is the same, it will join the currentTask
In the - Otherwise, even if the
Activity
theIntent
Is not specified inFLAG_ACTIVITY_NEW_TASK
Flags will also launch new onesTask
And willActivity
As for the
- If the
- Set up the
singleInstance
model- Set to
singleInstance
Modal activities are also system-unique in that there is only one instance object of the Activity in the system - At the same time the system will not be any other
Activity
Start to include theActivity
The instanceTask
In the - the
Activity
Is always theTask
The onlyActivity
- Set to
Usually, oneActivity
Once created, it will stay at a certainTask
Until it is destroyed
- However, if
Activity
theallowTaskReparenting
Property set totrue
theActivity
Can be in differentTask
Transfer between - However, this property is only enabled
Activity
theIntent
Set in theFLAG_ACTIVITY_RESET_TASK_IF_NEEDED
It only works when it’s marked
In addition to the above information, the Activity and Task logic can be found on the official website: Tasks and Return stack
For example, the following tips are important (excerpted from the official website) :
Use the “singleTask” and “singleInstance” startup modes only if your Activity has ACTION_MAIN and CATEGORY_LAUNCHER filters. They mark the Activity as always starting the task. For example, imagine what would happen without this filter: The intent starts the “singleTask” Activity, which then starts a new task that the user has spent some time on. The user then presses the home screen button. At this point, the task is moved to the background and is no longer visible. Now, the user cannot return to the task because it does not show up in the application launcher.
To understandClientTransactionHandler
The role of
ClientTransactionHandler is an important class that appears on Android 9.0 and is used to concatenate the entire lifecycle management of AMS and activities
We already know that the entry point for the application is the Main () function of the ActivityThread class. A closer look at the class structure shows that the ActivityThread inherits a special class. Are defined as follows
public final class ActivityThread extends ClientTransactionHandler {... }Copy the code
You can see that ActivityThread inherits the ClientTransactionHandler class. This class was added in Android 9.0 and the key definitions are as follows:
public abstract class ClientTransactionHandler {
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this); sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction); }...public abstract void handleDestroyActivity(...).;
public abstract void handlePauseActivity(...).;
public abstract void handleResumeActivity(...).;
public abstract void handleStopActivity(...).; .public abstract Activity handleLaunchActivity(...).;
public abstract void handleStartActivity(...).; .public abstract void handleNewIntent(...).; . }Copy the code
Class defines methods related to the declaration cycle, and as we can tactfully guess,AMS
Callback control for later life cycles should be implemented through this, and the related class inheritance is as follows:
Android abstracts the activities associated with the lifecycle. In the class defined above, the real business implementation includes:
LaunchActivityItem
Is to executelaunch activity
taskresume activity
byResumeActivityItem
implementationpause activity
byPauseActivityItem
implementationstop activity
byStopActivityItem
implementationdestroy activity
byDestoryActivityItem
implementation
ClientTransaction
Call logic of
Take a look at the call flow: The ApplicationThread class in ActivityThread has a scheduleTransaction() method,
The ApplicationThread class is a Binder service class that AMS calls as a client, as well as its scheduleTransaction() method
The scheduleTransaction() method is as follows:
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
Copy the code
The scheduleTransaction() method of ActivityThread, also known as ClientTransactionHandler, is called as follows:
void scheduleTransaction(ClientTransaction transaction) {
transaction.preExecute(this);
sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction);
}
Copy the code
An EXECUTE_TRANSACTION message is sent to the Handler implementation class H of ActivityThread. The message is handled as follows:
case EXECUTE_TRANSACTION:
final ClientTransaction transaction = (ClientTransaction) msg.obj;
mTransactionExecutor.execute(transaction);
if (isSystem()) {
transaction.recycle();
}
break;
Copy the code
Message processing were used in the mTransactionExecutor. The execute (), not surprisingly, will in TransactionExecutor execution logic, we look at:
public void execute(ClientTransaction transaction) {
final IBinder token = transaction.getActivityToken();
executeCallbacks(transaction);
executeLifecycleState(transaction);
mPendingActions.clear();
}
public void executeCallbacks(ClientTransaction transaction) {
final List<ClientTransactionItem> callbacks = transaction.getCallbacks();
if (callbacks == null) {
return; }...final int size = callbacks.size();
for (int i = 0; i < size; ++i) { ...... item.execute(mTransactionHandler, token, mPendingActions); item.postExecute(mTransactionHandler, token, mPendingActions); . }}private void executeLifecycleState(ClientTransaction transaction) {
final ActivityLifecycleItem lifecycleItem = transaction.getLifecycleStateRequest();
if (lifecycleItem == null) {
// No lifecycle request, return early.
return; }...// A very important method
cycleToPath(r, lifecycleItem.getTargetState(), true /* excludeLastState */);
// Execute the final transition with proper parameters.
lifecycleItem.execute(mTransactionHandler, token, mPendingActions);
lifecycleItem.postExecute(mTransactionHandler, token, mPendingActions);
}
Copy the code
As you can see, the item.execute() and LifecycleItem.execute () methods were finally executed on the executeCallbacks() and executeLifecycleState() sides, respectively
What are the purposes of executeCallbacks() and executeLifecycleState()? Based on the class diagram, we can infer as follows:
executeCallbacks()
Traversal performsClientTransaction
In the classList<ClientTransactionItem> mActivityCallbacks
Elements of a setClientTransactionItem
The direct subclass implementation of the class onlyLaunchActivityItem
class- That is to say,
executeCallbacks()
The main implementation islaunch activity
Notification operation of
executeLifecycleState()
Execution isClientTransaction
In the classActivityLifecycleItem mLifecycleStateRequest
mLifecycleStateRequest
Referred to asfinal state
- As you can see from the inheritance relationship,
resume activity
,pasue activity
,stop activity
,destory activity
Are all here
Once you look at the call flow, you’ll notice that there is no StartActivityItem in the implementation class. Why? So how do I call onStart()? The core lies in the cycleToPath() function
TransactionExecutor.cycleToPath()
Android does not define all *ActivityItem classes for the Activity lifecycle. For example, StartActivityItem does not exist.
Note the constant definition of the ActivityLifecycleItem in the class diagram. Android uses cycleToPath() to take a more subtle approach. The core logic is:
- To specify a
Activity
thefinal state
- According to the
Activity
To calculate the required state during the process and save it in the collection - Finally, the states in the collection are executed sequentially
Take the realStartActivityLocked() method later in this article
- will
LaunchActivityItem
Object of type added tocallback
In theTransactionExecutor
Will be performedLaunchActivityItem
class- After the execution
Activity
Into theON_CREATE
state
- Method specified in
final state
forResumeActivityItem
TransactionExecutor
throughcycleToPath()
Calculates the current state andfinal state
The difference of- The current status is
ON_CREATE
State,final state
forON_RESUME
TransactionExecutor
Through the help classgetLifecyclePath
Method to collate the missing state between the two into a collection- And then call
performLifecycleSequence()
Circulation processing
PerformLifecycleSequence () :
private void performLifecycleSequence(ActivityClientRecord r, IntArray path) {
final int size = path.size();
for (int i = 0, state; i < size; i++) {
state = path.get(i);
switch (state) {
caseON_CREATE: mTransactionHandler.handleLaunchActivity(...) ;break;
case ON_START:
mTransactionHandler.handleStartActivity(r, mPendingActions);
break;
caseON_RESUME: mTransactionHandler.handleResumeActivity(...) ;break;
caseON_PAUSE: mTransactionHandler.handlePauseActivity(...) ;break;
caseON_STOP: mTransactionHandler.handleStopActivity(...) ;break;
caseON_DESTROY: mTransactionHandler.handleDestroyActivity(...) ;break;
caseON_RESTART: mTransactionHandler.performRestartActivity(...) ;break;
default:
throw new IllegalArgumentException("Unexpected lifecycle state: "+ state); }}}Copy the code
PauseActivityItem
Call analysis of
Using the PauseActivityItem class as an example, let’s look at the specific execution logic:
public class PauseActivityItem extends ActivityLifecycleItem {...@Override
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {... client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions,"PAUSE_ACTIVITY_ITEM"); . }}Copy the code
You execute the ClientTransactionHandler abstract class, which is essentially the handlePauseActivity() method of the ActivityThread class.
HandlePauseActivity () method calls the performPauseActivity ActivityThread class () method, which is the last call to performPauseActivityIfNeeded () method, the code is as follows:
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {... mInstrumentation.callActivityOnPause(r.activity); . }Copy the code
The callActivityOnPause() method of the Instrumentation class is executed as follows:
public void callActivityOnPause(Activity activity) {
activity.performPause();
}
Copy the code
Very succinct, continue to check:
public class Activity{
final void performPause(a) {
mDoReportFullyDrawn = false;
mFragments.dispatchPause();
mCalled = false;
onPause();
writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
mResumed = false; . }}Copy the code
Do you have any! Do you have any! onPause(); Finally called…
We’ve found the flow of the call from the application side, but how does it get triggered for AMS?
Next, let’s examine the Activity launch process. During the Activity launch process, we can find an example of AMS triggering the declaration cycle
Start theActivity
To explore the calling details of the Activity lifecycle, start with the most familiar place, the startActivity (Intent Intent) method of the Activity object
Activty.startActivty()
The startActivity (Intent Intent) method is called as follows:
class Activity{
public void startActivity(Intent intent, @Nullable Bundle options) {
if(options ! =null) {
startActivityForResult(intent, -1, options);
} else {
startActivityForResult(intent, -1); }}public void startActivityForResult(...). {... Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, who, intent, requestCode, options); . }}class Instrumentation{
public ActivityResult execStartActivity(...). { IApplicationThread whoThread = (IApplicationThread) contextThread; .try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
intresult = ActivityManager.getService() .startActivity(...) ; checkStartActivityResult(result, intent); }catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null; }}class ActivityManagerService{
public final int startActivity(...). {
returnstartActivityAsUser(...) ; }public final int startActivityAsUser(...). {...return mActivityStartController.obtainStarter(intent, "startActivityAsUser")... .execute(); }}Copy the code
We see that the last thing we call is the AMS startActivityAsUser method. If you trace the call to the startActivityAsUser method, the ActivityStarter class’s execute() method is used to start the Activity:
class ActivityStater{
int execute(a) {
try {
if (mRequest.mayWait) {
returnstartActivityMayWait(...) ; }else {
return startActivity(...);
}
} finally{ onExecutionComplete(); }}}Copy the code
We see that execute() has two methods to start the Activity, and we’ll continue with the startActivityMayWait() method, since we’ll end up in startActivity() as well.
ActivityStarter.startActivityMayWait()
The brief code is as follows:
private int startActivityMayWait(...). {...// Get information about the Activity to start
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
synchronized (mService) {
......
intres = startActivity(caller, ...) ; .if(outResult ! =null) { // The result needs to be returned
outResult.result = res;
final ActivityRecord r = outRecord[0];
switch(res) {
case START_SUCCESS: {
// Add to a specific collection
mSupervisor.mWaitingActivityLaunched.add(outResult);
do {
try {
// Wait for the Activity to start in the application process
mService.wait();
} catch (InterruptedException e) {
}
} while(outResult.result ! = START_TASK_TO_FRONT && ! outResult.timeout && outResult.who ==null); .break; }... }}returnres; }}Copy the code
The startActivityMayWait() method flows as follows:
- First call
resolveActivity()
Method to get theActivity
The information of - get
Activity
After the message, continue the callstartActivity()
Method to continue the startupActivity
- If you start
Activity
If the application needs to get the return resultmService
The object’swait()
Method suspends the thread to wait for the result of starting
Here’s the code that calls the startActivity() method on ActivityStarter. Let’s look at some of the details:
private int startActivity(IApplicationThread caller, ...) {
interr = ActivityManager.START_SUCCESS; .if(caller ! =null) {
// Get information about the process that started the Activity
callerApp = mService.getRecordForAppLocked(caller);
if(callerApp ! =null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else{ err = ActivityManager.START_PERMISSION_DENIED; }}final intuserId = aInfo ! =null&& aInfo.applicationInfo ! =null
? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0; .// Omit a lot of error checking
// Check the relevant permissions of the caller
booleanabort = ! mSupervisor.checkStartAnyActivityPermission(...) ;// Check whether the Intent firewall blocks the Intentabort |= ! mService.mIntentFirewall.checkStartActivity(...) ; .if(mService.mController ! =null) {
try {
// The IActivityControler interface that listens to the Activity change is notified of the Activity start messageIntent watchIntent = intent.cloneFilter(); abort |= ! mService.mController.activityStarting(watchIntent, aInfo.applicationInfo.packageName); }catch (RemoteException e) {
mService.mController = null; }}...if (abort) {
......// If abort is true, exit
returnSTART_ABORTED; }...// Create an ActivityRecord object
ActivityRecord r = newActivityRecord(...) ;if(outActivity ! =null) {
outActivity[0] = r; }...// The ActivityStack that the current user is operating on
final ActivityStack stack = mSupervisor.mFocusedStack;
// Check whether the caller has permission to switch processes in case of frequent process switching
if (voiceSession == null && (stack.getResumedActivity() == null|| stack.getResumedActivity().info.applicationInfo.uid ! = realCallingUid)) {if(! mService.checkAppSwitchAllowedLocked(callingPid, callingUid, realCallingPid, realCallingUid,"Activity start")) {
// For cases where you cannot switch processes, place the Activity information in the MpendingActivityLauncher list
mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp));
ActivityOptions.abort(checkedOptions);
returnActivityManager.START_SWITCHES_CANCELED; }}if (mService.mDidAppSwitch) {
mService.mAppSwitchesAllowedTime = 0;
} else {
mService.mDidAppSwitch = true;// Turn on the switch to allow switching between processes
}
// To start the pending activities, you start each Activity in the MpendingActivityLauncher list.
// startActivity is also called
// In most cases the MPendingActivitylauncher list is blank
mController.doPendingActivityLaunches(false); .// Call startActivity another overloaded method, taking ActivityRecord as the first argument
returnstartActivity(r, ...) ; }private int startActivity(final ActivityRecord r, ...) {
intresult = START_CANCELED; . result = startActivityUnchecked(r, ...) ; .return result;
}
Copy the code
I don’t need to go into too much detail here, but it’s important to understand how the Activity method is called. The last call is the startActivityUnchecked() method.
ActivityStarter.startActivityUnchecked()
The method is as follows:
private int startActivityUnchecked(final ActivityRecord r, ...) {
// Initialize the environment and lunchModeFlags
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
computeLaunchingTaskFlags();
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
// Determine whether the Activity needs to insert a new Task if reusedActivity is not empty
// 1. Set FLAG_ACTIVITY_NEW_TASK:
// 2. Start mode singleTask:
// 3. The startup mode is singleInstanceActivityRecord reusedActivity = getReusableIntentActivity(); .final booleandontStart = top ! =null && mStartActivity.resultTo == null&& top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId && top.app ! =null&& top.app.thread ! =null&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) ! =0
|| isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
if (dontStart) { // No need to start the case
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
if(mDoResume) { mSupervisor.resumeFocusedStackTopActivityLocked(); }... deliverNewIntent(top); .return START_DELIVERED_TO_TOP;
}
boolean newTask = false;
finalTaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord ! =null)? mSourceRecord.getTask() :null;
// Determine whether the current Activity needs a new Task
int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null&&! mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) ! =0) {
newTask = true;
result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
} else if(mSourceRecord ! =null) {
result = setTaskFromSourceRecord();
} else if(mInTask ! =null) {
result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.setTaskToCurrentTopOrCreateNewTask(); }.../ / start the Activity
// startActivityLocked basically adds an ActivityRecord object to the top of the Task
// Also add Task to the top of mTaskHistory
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
// Make the Activity visible using WindowManager
if (mDoResume) {
final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked();
if(! mTargetStack.isFocusable() || (topTaskActivity ! =null&& topTaskActivity.mTaskOverlay && mStartActivity ! = topTaskActivity)) { mTargetStack.ensureActivitiesVisibleLocked(null.0, !PRESERVE_WINDOWS);
mService.mWindowManager.executeAppTransition(); // The animation should be executed to switch between applications
} else{... mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity, mOptions); }}else if(mStartActivity ! =null) { mSupervisor.mRecentTasks.add(mStartActivity.getTask()); }...return START_SUCCESS;
}
Copy the code
The startActivityUnchecked() method uses the Intent flag and Activity properties to determine the Activity’s Task and then pushes it to the top of the stack. We’ll skip over the details. Need to focus on the method is mSupervisor resumeFocusedStackTopActivityLocked () method call. Trace the call, the execution is resumeTopActivityInnerLocked ActivityStack class () method
ActivityStack.resumeTopActivityInnerLocked()
We already know resumeFocusedStackTopActivityLocked () method will eventually call resumeTopActivityInnerLocked ActivityStack class () method.
ResumeTopActivityInnerLocked () method is the role of the main in the Activity displayed on the top of the stack, but before that, the old Activity (variable mResumedActivity reference is) also showed on the screen. The method content is as follows:
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
if(! mService.mBooting && ! mService.mBooted) {// Not ready yet!
return false;
}
// Find the Activity to start from mTaskHistory
// This should be done because the Activity is already on the stack
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
final booleanhasRunningActivity = next ! =null; .if(! hasRunningActivity) {// There are no activities left in the stack, let's look somewhere else.
return resumeTopActivityInNextFocusableStack(prev, options, "noMoreActivities");
}
next.delayedResume = false;
// If the currently displayed Activity is the Activity to start, return directly
if (mResumedActivity == next && next.isState(RESUMED)
&& mStackSupervisor.allResumedActivitiesComplete()) {
executeAppTransition(options);
return false;
}
// If you are hibernating or shutting down, return directly
if (shouldSleepOrShutDownActivities()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
executeAppTransition(options);
return false;
}
// User status check
if(! mService.mUserController.hasStartedUserState(next.userId)) {return false;
}
// The Activity to be started is removed from the relevant queue
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(next);
// Check if any Activity is being paused
if(! mStackSupervisor.allPausedActivitiesComplete()) {return false;
}
// Set applicationInfo to launchmStackSupervisor.setLaunchSource(next.info.applicationInfo.uid); .boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
if(mResumedActivity ! =null) {
// Suspend the current Activity
// startPausingLocked() triggers onPause() for the old Activity
pausing |= startPausingLocked(userLeaving, false, next, false); }... ActivityStack lastStack = mStackSupervisor.getLastStack();if(next.app ! =null&& next.app.thread ! =null) {
// If the application in which the Activity resides already exists, just display the Activity.synchronized(mWindowManager.getWindowManagerLock()) {
// This activity is now becoming visible.
if(! next.visible || next.stopped || lastActivityTranslucent) { next.setVisibility(true); }...try {
finalClientTransaction transaction = ClientTransaction.obtain(next.app.thread, next.appToken); .// Add ActivityResultItem if the Activity is still waiting for results to return.
// The onActivityResult callback is executed
ArrayList<ResultInfo> a = next.results;
if(a ! =null) {
final int N = a.size();
if(! next.finishing && N >0) {
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Delivering results to " + next + ":"+ a); transaction.addCallback(ActivityResultItem.obtain(a)); }}// Add NewIntentItem, where onNewIntent is executed
if(next.newIntents ! =null) {
transaction.addCallback(NewIntentItem.obtain(next.newIntents,
false /* andPause */)); } transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.repProcState, mService.isNextTransitionForward())); mService.getLifecycleManager().scheduleTransaction(transaction); . }catch (Exception e) {
// Whoops, need to restart this activity!. mStackSupervisor.startSpecificActivityLocked(next,true.false);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true; }}... }else {
// Whoops, need to restart this activity!. mStackSupervisor.startSpecificActivityLocked(next,true.true); }...return true;
}
Copy the code
Longer the streamline resumeTopActivityInnerLocked () code, the core logic is as follows:
- First, through the
startPausingLocked()
Suspension of the oldActivity
.startPausingLocked()
The method is as follows:final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, boolean pauseImmediately) {... mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving, prev.configChangeFlags, pauseImmediately)); . }Copy the code
- This is the same as the front
ClientTransaction
Echo up, heh heh
- This is the same as the front
- if
Activity
The application is already started. YesActivity
Display processing, createResumeActivityItem
Make life cycle notifications- Eventually lead to
Activity
The object’sonResume()
Method execution
- Eventually lead to
- If the application has not yet been started
startSpecificActivityLocked()
Method To continue processing, the method is as follows:void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Get the Activity's corresponding process ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); if(app ! =null&& app.thread ! =null) { try{...// If application processes already exist, execute realStartActivityLocked() // andResume = true realStartActivityLocked(r, app, andResume, checkConfig); // Then return return; } catch (RemoteException e) { } } // The Activity's corresponding process is empty. Create a new process through AMS's startProcessLocked() mService.startProcessLocked(r.processName, r.info.applicationInfo, true.0."activity", r.intent.getComponent(), false.false.true); } Copy the code
- The core approach is
realStartActivityLocked()
, even in the case of restarting the process, the final execution is the samerealStartActivityLocked()
- The core approach is
ActivityStackSupervisor.realStartActivityLocked()
For the realStartActivityLocked() method, let’s take a quick look at the life cycle:
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {...// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(app.thread,
r.appToken);
// Add LaunchActivityItem, which triggers the onCreate method
clientTransaction.addCallback(LaunchActivityItem.obtain(newIntent(r.intent), ...) ;// Set the final state, resume or pause
final ActivityLifecycleItem lifecycleItem;
// According to the previous call parameters, andResume = true
if (andResume) {
// Set the final status to ON_RESUME
lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// Schedule transaction.mService.getLifecycleManager().scheduleTransaction(clientTransaction); .return true;
}
Copy the code
The LaunchActivityItem and ResumeActivityItem classes are added to the method, and the scheduleTransaction() method is called.
LaunchActivityItem is one of the more complex invocation logic
Using the LaunchActivityItem class as an example, let’s look at tracking downgrades:
public class LaunchActivityItem extends ClientTransactionItem {
@Override
public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) {... client.handleLaunchActivity(r, pendingActions,null /* customIntent */); . }}Copy the code
This calls the handleLaunchActivity() method in ActivityThread:
public Activity handleLaunchActivity(ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent) {...finalActivity a = performLaunchActivity(r, customIntent); .return a;
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {... Activity activity =null;
try{ java.lang.ClassLoader cl = appContext.getClassLoader(); activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); . }catch (Exception e) {
...
}
try{...if(activity ! =null) {... activity.mCalled =false;
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
if(! activity.mCalled) {throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
}
// Set the state to ON_CREATE
r.setState(ON_CREATE);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
......
}
return activity;
}
Copy the code
Is called Instrumentation. CallActivityOnCreate () method, the content is as follows:
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
}
Copy the code
The final pass is to call the activity.performCreate () method:
final void performCreate(Bundle icicle, PersistableBundle persistentState) {...if(persistentState ! =null) {
onCreate(icicle, persistentState);
} else{ onCreate(icicle); }... }Copy the code
At this point, the LaunchActivityItem logic ends and the onCreate() callback is executed, setting the state to ON_CREATE.
However, since the final state in realStartActivityLocked() is set to ON_RESUME, the current Activity state is not final, so The TransactionExecutor will continue.