Android Framework- AMS 之 Activity-暂停

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

我抓紧看看吧,省的别人问我,装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() 会回调到 ActivityClientControlleractivityPaused()

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);
}

这里会调用到 ActivityRecordactivityPaused()

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() 但是这里参数分别是truenull

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(),执行生命周期的时候,会去进行判断。
相关推荐
2501_916013742 小时前
App 上架服务全流程解析,iOS 应用代上架、ipa 文件上传工具、TestFlight 测试与苹果审核实战经验
android·ios·小程序·https·uni-app·iphone·webview
建群新人小猿3 小时前
客户标签自动管理:标签自动化运营,画像持久保鲜
android·java·大数据·前端·git
一直向钱4 小时前
android 自定义样式 Toast 实现(兼容 Android 4.1+~Android 16(API 16))
android
一直向钱4 小时前
android SharedPreferences 工具类 * 兼容 Android 16+ (API 16)
android
2501_915909064 小时前
App Store 上架完整流程解析,iOS 应用发布步骤、ipa 文件上传工具、TestFlight 测试与苹果审核经验
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_916008894 小时前
iOS 26 全景揭秘,新界面、功能创新、兼容挑战与各种工具在新版系统中的定位
android·macos·ios·小程序·uni-app·cocoa·iphone
小趴菜822714 小时前
安卓接入Kwai广告源
android·kotlin
2501_9160137414 小时前
iOS 混淆与 App Store 审核兼容性 避免被拒的策略与实战流程(iOS 混淆、ipa 加固、上架合规)
android·ios·小程序·https·uni-app·iphone·webview
程序员江同学15 小时前
Kotlin 技术月报 | 2025 年 9 月
android·kotlin