今天在和哥们闲聊,聊到之前看的启动页面的流程,哥们突然问了一句。 在新的页面启动之前,老的页面做了什么操作,你知道么?

我抓紧看看吧,省的别人问我,装X失败咋办。
从ActivityStarter.startActivityInner()
开始
java
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
final boolean newTask = targetTask == null;
//省略....
if (mTargetRootTask == null) {
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
mOptions);
}
if (newTask) {
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
}
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
mOptions, sourceRecord);
computeTargetTask()
的作用是匹配看看启动的页面有没有可以塞的Task
。一般是null
,这个和启动模式有关。 getOrCreateRootTask()
的作用是构建了一个Task
挂载到了taskDisplayArea
上。 也就是 DefaultTaskDisplayArea
下。
mTargetRootTask.startActivityLocked()
里 调用显示启动窗口。
ini
mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask,
isTaskSwitch, sourceRecord);
java
//RootWindowContainer.getOrCreateRootTask();
//省略...
if (taskDisplayArea == null) {
taskDisplayArea = getDefaultTaskDisplayArea();
}
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, sourceTask,
launchParams, launchFlags, activityType, onTop);
继续下看
java
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
mOptions, sourceRecord);
这部分就是将要启动的ActivityRecord
放到Task
的最上面,然后启动窗口动画。 到这里为止 就是构建Task
挂载到DefaultTaskDisplayArea
下,并将我们要启动的ActivityRecord
放到Task
最上层,启动窗口动画。
继续看
java
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
--> targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
deferPause);
-->resumeTopActivityInnerLocked(prev, options, deferPause);
-->
topFragment.resumeTopActivity(prev, options, deferPause);
-->taskDisplayArea.pauseBackTasks(next);
//TaskFragment 注意这里参数为false 和resuming不为null
-->leafTask.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")
-->schedulePauseActivity()
-->completePause()
TaskFragment.completePause()
主要就是设置 ActivityRecord
设置state
为PAUSED
java
if (prev != null) {
prev.setWillCloseOrEnterPip(false);
final boolean wasStopping = prev.isState(STOPPING);
//ActivityRecord设置state 为PAUSED
prev.setState(PAUSED, "completePausedLocked");
这里会导致页面的生命周期发生变化。 会进入 PauseActivityItem
的逻辑。
java
//PauseActivityItem
@Override
public void execute(ClientTransactionHandler client, ActivityClientRecord r,
PendingTransactionActions pendingActions) {
client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, mAutoEnteringPip,
pendingActions, "PAUSE_ACTIVITY_ITEM");
}
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
if (mDontReport) {
return;
}
ActivityClient.getInstance().activityPaused(token);
}
execute()
回调Activity
的 onPause()
postExecute()
会回调到 ActivityClientController
的activityPaused()
java
//ActivityClientController
@Override
public void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused");
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
r.activityPaused(false);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
Binder.restoreCallingIdentity(origId);
}
这里会调用到 ActivityRecord
的activityPaused()
java
//ActivityRecord
void activityPaused(boolean timeout) {
final TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
//移除超时
removePauseTimeout();
final ActivityRecord pausingActivity = taskFragment.getPausingActivity();
if (pausingActivity == this) {
mAtmService.deferWindowLayout();
try {
taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */);
} finally {
mAtmService.continueWindowLayout();
}
return;
}
//省略...
}
mDisplayContent.handleActivitySizeCompatModeIfNeeded(this);
mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
}
这里又进入了taskFragment.completePause()
但是这里参数分别是true
和null
java
//TaskFragment
void completePause(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
if (prev != null) {
prev.setWillCloseOrEnterPip(false);
final boolean wasStopping = prev.isState(STOPPING);
prev.setState(PAUSED, "completePausedLocked");
if (prev.finishing) {
prev = prev.completeFinishing(false /* updateVisibility */,
"completePausedLocked");
} else if (prev.hasProcess()) {
if (prev.deferRelaunchUntilPaused) {
prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
} else if (wasStopping) {
prev.setState(STOPPING, "completePausedLocked");
} else if (!prev.isVisibleRequested() || shouldSleepOrShutDownActivities()) {
prev.addToStopping(true /* scheduleIdle */, false /* idleDelayed */,
"completePauseLocked");
}
} else {
ProtoLog.v(WM_DEBUG_STATES, "App died during pause, not stopping: %s", prev);
prev = null;
}
if (prev != null) {
prev.stopFreezingScreenLocked(true /*force*/);
}
mPausingActivity = null;
}
//这里主要是找到新启动的页面,并进入onResume状态
if (resumeNext) {
final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev,
null /* targetOptions */);
} else {
// checkReadyForSleep();
final ActivityRecord top =
topRootTask != null ? topRootTask.topRunningActivity() : null;
if (top == null || (prev != null && top != prev)) {
mRootWindowContainer.resumeFocusedTasksTopActivities();
}
}
}
if (prev != null) {
prev.resumeKeyDispatchingLocked();
}
mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
if (mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause
|| (getDisplayArea() != null && getDisplayArea().hasPinnedTask())) {
mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
}
}
简单理解,就是在老页面onPause()
以后 会去检查新的页面是否已经准备好,如果没有准备好则等待新的页面符合条件后进行。 如果新的页面此刻没有完成构建。 在 realStartActivityLocked()
方法中,会判断老的页面是否都已经onPause()
,才去构建新的页面,页面构建完成后通过调用 rootTask.minimalResumeActivityLocked(r)
将状态推进到onResume()
。
java
//ActivityTaskSupervisor
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
if (!mRootWindowContainer.allPausedActivitiesComplete()) {
return false;
}
//省略...
if (andResume && readyToResume()) {
//执行onResume
rootTask.minimalResumeActivityLocked(r);
}
总结一下:
- 新的页面构建的时候,会构建新的
Task
挂载到DefaultTaskDisplayArea
下, 会将新构建的ActivityRecord
放置到Task
的最上层,并启动启动窗口。 - 新的
Activity
在构建之前,会判断所有老的页面是否进入了隐藏。如果符合条件会进入构建流程,并在构建完成后推进到onResume()
。 - 老的页面会通过
ActivityRecord的setState(PAUSED
)的形式,进入PauseActivityItem
的逻辑,在完成自身onPause()
后,会检查新的页面是否可以启动。 Application
的构建不受到老页面onPause()
的限制,但是在走到realStartActivityLocked()
,执行生命周期的时候,会去进行判断。