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(),执行生命周期的时候,会去进行判断。
相关推荐
雨白36 分钟前
优雅地处理协程:取消机制深度剖析
android·kotlin
leon_zeng01 小时前
更改 Android 应用 ID (ApplicationId) 后遭遇记
android·发布
2501_916007472 小时前
iOS 混淆工具链实战,多工具组合完成 IPA 混淆与加固(iOS混淆|IPA加固|无源码混淆|App 防反编译)
android·ios·小程序·https·uni-app·iphone·webview
Jeled4 小时前
Retrofit 与 OkHttp 全面解析与实战使用(含封装示例)
android·okhttp·android studio·retrofit
ii_best7 小时前
IOS/ 安卓开发工具按键精灵Sys.GetAppList 函数使用指南:轻松获取设备已安装 APP 列表
android·开发语言·ios·编辑器
2501_915909067 小时前
iOS 26 文件管理实战,多工具组合下的 App 数据访问与系统日志调试方案
android·ios·小程序·https·uni-app·iphone·webview
limingade8 小时前
手机转SIP-手机做中继网关-落地线路对接软交换呼叫中心
android·智能手机·手机转sip·手机做sip中继网关·sip中继
RainbowC08 小时前
GapBuffer高效标记管理算法
android·算法
程序员码歌9 小时前
豆包Seedream4.0深度体验:p图美化与文生图创作
android·前端·后端
、花无将10 小时前
PHP:下载、安装、配置,与apache搭建
android·php·apache