Android Framework AMS(06)startActivity分析-3(补充:onPause和onStop相关流程解读)

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:本章节主要解读AMS通过startActivity启动Activity的整个流程的补充,更新了startActivity流程分析部分。

一般来说,有Activity启动,就有Activity退到后台。那么后者这个操作具体是怎样的呢?我们以startPausingLocked方法和stopActivityLocked方法为入口分别对到activity的onPause和AMS到onStop流程进行分析。

该部分是AMS.startActivity运行中生命周期的补充,毕竟startActivity关注onCreate、onStart、onResume ,但activity的生命周期还涉及onPause、onStop、onDestroy。本章主要介绍onPause、onStop。最后以onStop为例介绍了下APP中回调超时的设计理念。

1 startPausingLocked方法解读(onPause处理)

在之前AMS.startActivity的流程分析中执行resume相关操作时就已经开始执行startPausingLocked方法了。startPausingLocked的调用入口是resume相关函数,代码如下所示:

//ActivityStack//关键流程:step1final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {// 检查是否已经在执行恢复顶部 Activity 的操作,防止递归调用if (mStackSupervisor.inResumeTopActivity) {return false;   // 如果已经在执行恢复操作,则直接返回 false}// 初始化结果变量,用于记录恢复操作是否成功boolean result = false;try {// 设置一个标志,表示正在执行恢复顶部 Activity 的操作,防止递归mStackSupervisor.inResumeTopActivity = true;//锁屏状态相关处理//...//关键方法:调用内部方法实际执行恢复顶部 Activity 的操作result = resumeTopActivityInnerLocked(prev, options);} finally {// 恢复完成后,重置正在执行恢复操作的标志mStackSupervisor.inResumeTopActivity = false;}// 返回恢复操作的结果return result;}//关键流程:step2final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");//... boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);if (mResumedActivity != null) {pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);}if (pausing) {if (next.app != null && next.app.thread != null) {mService.updateLruProcessLocked(next.app, true, null);}return true;}//...return true;}

这里调用了startPausingLocked方法,当新启动一个activity时,系统将先处理当前的activity,即调用该方法来pause当前activity,代码实现如下:

//ActivityStackfinal boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,boolean dontWait) {// 如果已经在暂停一个 Activity,完成暂停操作。if (mPausingActivity != null) {completePauseLocked(false);}// 记录当前处于前台的 Activity。ActivityRecord prev = mResumedActivity;// 如果没有前台 Activity,且不是正在恢复状态,尝试恢复顶层 Activity。if (prev == null) {if (!resuming) {mStackSupervisor.resumeTopActivitiesLocked();}return false; // 如果没有前台 Activity,返回 false。}// 如果当前 Activity 没有父 Activity,暂停所有子栈。if (mActivityContainer.mParentActivity == null) {mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping, resuming, dontWait);}// 将当前前台 Activity 设置为 null,准备暂停。mResumedActivity = null;// 标记 prev 为正在暂停的 Activity。mPausingActivity = prev;// 记录最后一个暂停的 Activity。mLastPausedActivity = prev;// 确定最后一个没有历史记录的 Activity。mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0|| (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;// 更新 prev Activity 的状态为 PAUSING。prev.state = ActivityState.PAUSING;// 更新任务的活动时间。prev.task.touchActiveTime();// 清除启动时间。clearLaunchTime(prev);// 获取顶层运行的 Activity。final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();// 如果支持最近任务并且下一个 Activity 为空或者不显示或者不在同一个任务或者 UI 休眠,则更新缩略图。if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {prev.updateThumbnailLocked(screenshotActivities(prev), null);}// 停止完全绘制的跟踪(可能是性能监控的一部分)。stopFullyDrawnTraceIfNeeded();// 更新 CPU 统计信息。mService.updateCpuStats();// 如果 prev 的应用和线程不为空,发送暂停 Activity 的请求。if (prev.app != null && prev.app.thread != null) {try {mService.updateUsageStats(prev, false);// 关键方法:调用当前Activity所在进程的schedulePauseActivity方法prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,userLeaving, prev.configChangeFlags, dontWait);} catch (Exception e) {// 异常处理(代码省略)。}} else {// 如果应用或线程为空,清除暂停的 Activity 记录。mPausingActivity = null;mLastPausedActivity = null;mLastNoHistoryActivity = null;}// 如果系统不是在休眠或关闭状态,获取启动锁。if (!mService.isSleepingOrShuttingDown()) {mStackSupervisor.acquireLaunchWakelock();}// 如果正在暂停一个 Activity,处理是否等待暂停完成。if (mPausingActivity != null) {if (!uiSleeping) {// 如果 UI 不在休眠状态,暂停按键分发。prev.pauseKeyDispatchingLocked();}if (dontWait) {// 如果不需要等待,完成暂停并返回 false。completePauseLocked(false);return false;} else {// 如果需要等待,发送暂停超时的消息,并设置超时时间。Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);msg.obj = prev;prev.pauseTime = SystemClock.uptimeMillis();mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);return true;}} else {// 如果没有 Activity 正在暂停,尝试恢复顶层 Activity。if (!resuming) {mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);}return false;}}

startPausingLocked 方法用于处理 Activity 的暂停逻辑。它首先检查是否有正在进行的暂停操作,如果有,则完成它。然后,它检查是否有前台 Activity,如果没有,则尝试恢复顶层 Activity。如果有前台 Activity,它会更新一些状态和变量,准备暂停操作。如果系统支持最近任务并且条件满足,它会更新 Activity 的缩略图。然后注意:关键点来了,它发送一个暂停 Activity 的请求到应用线程。如果系统不是在休眠或关闭状态,它会获取一个启动锁。最后,根据是否需要等待暂停完成,它要么立即返回,要么设置一个超时消息来处理暂停超时情况。这个方法返回一个布尔值,表示是否成功启动了暂停操作。

接下来关注schedulePauseActivity方法实现,主要是通过消息处理最后调用handlePauseActivity方法,过程中的代码实现如下:

//ActivityThread//ApplicationThreadpublic final void schedulePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges, boolean dontReport) {sendMessage(finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,token,(userLeaving ? 1 : 0) | (dontReport ? 2 : 0),configChanges);}//...//Handler消息处理private class H extends Handler {public void handleMessage(Message msg) {switch (msg.what) {//...case PAUSE_ACTIVITY:handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,(msg.arg1&2) != 0);maybeSnapshot();break;//...}}//...}//...private void handlePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges, boolean dontReport) {// 根据 token 查找对应的 ActivityClientRecord 对象。ActivityClientRecord r = mActivities.get(token);// 如果找到了对应的 ActivityClientRecord。if (r != null) {if (userLeaving) { // 如果用户正在离开 Activity,执行相关的处理。performUserLeavingActivity(r);}r.activity.mConfigChangeFlags |= configChanges;// 关键方法:执行暂停 Activity 的操作。performPauseActivity(token, finished, r.isPreHoneycomb());// 如果应用的 target SDK 版本低于 Honeycomb(3.0),等待所有队列工作完成。if (r.isPreHoneycomb()) {QueuedWork.waitToFinish();}// 如果不应该报告 Activity 暂停,跳过报告步骤。if (!dontReport) {try {// 关键方法:向 ActivityManager 报告 Activity 已暂停。ActivityManagerNative.getDefault().activityPaused(token);} catch (RemoteException ex) {//...}}mSomeActivitiesChanged = true;}}

这里开始我们关注关键方法performPauseActivity和通知AMS做其他处理的操作。详细解读如下。

1.1 performPauseActivity方法解读

接下来,一条路线是为了启动activity并调用activity的onPause方法,关键方法为:

//ActivityThread//关键流程:step1final Bundle performPauseActivity(IBinder token, boolean finished,boolean saveState) {ActivityClientRecord r = mActivities.get(token);return r != null ? performPauseActivity(r, finished, saveState) : null;}//关键流程:step2final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,boolean saveState) {try {// 如果 Activity 没有完成(即没有调用过 finish()),并且需要保存状态,则调用 onSaveInstanceState()。if (!r.activity.mFinished && saveState) {callCallActivityOnSaveInstanceState(r);}// 标记 Activity 为已调用 onPause() 状态。r.activity.mCalled = false;// 调用 Activity 的 onPause() 方法。mInstrumentation.callActivityOnPause(r.activity);} catch (SuperNotCalledException e) {//...}// 标记 Activity 为已暂停状态。r.paused = true;// 获取所有注册的 onPaused 监听器,这些监听器将在 Activity 暂停时被通知。ArrayList<OnActivityPausedListener> listeners;synchronized (mOnPauseListeners) {listeners = mOnPauseListeners.remove(r.activity);}// 获取监听器列表的大小。int size = (listeners != null ? listeners.size() : 0);// 遍历所有监听器,调用它们的 onPaused() 方法。for (int i = 0; i < size; i++) {listeners.get(i).onPaused(r.activity);}// 如果 Activity 没有完成并且需要保存状态,则返回保存的状态 Bundle;否则返回 null。return !r.activity.mFinished && saveState ? r.state : null;}

这里较为简单,主要就是调用activty的onPause方法了(mInstrumentation.callActivityOnPause)。另一条路线是调用完通知AMS。接下来看看通知AMS都干了些啥。

1.2 通知AMS处理Pause的相关操作

在handlePauseActivity中最后部分执ActivityManagerNative.getDefault().activityPaused(token);调用到activityPaused方法,代码实现如下:

//ActivityManagerService//...@Overridepublic final void activityPaused(IBinder token) {final long origId = Binder.clearCallingIdentity();synchronized(this) {// 根据提供的 token 查找对应的 ActivityStack。ActivityStack stack = ActivityRecord.getStackLocked(token);if (stack != null) {// 关键方法:传递 token 和 false。stack.activityPausedLocked(token, false);}}Binder.restoreCallingIdentity(origId);}

这里主要关注activityPausedLocked方法的实现,代码实现如下:

//ActivityStack//关键流程:step1final void activityPausedLocked(IBinder token, boolean timeout) {// 根据提供的 token 查找对应的 ActivityRecordfinal ActivityRecord r = isInStackLocked(token);if (r != null) {// 从消息队列中移除任何与 PAUSE_TIMEOUT_MSG 相关的消息,避免暂停超时mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);// 如果当前正在暂停的 Activity 与找到的 ActivityRecord 相匹配if (mPausingActivity == r) {// 关键方法:完成暂停操作,传递 truecompletePauseLocked(true);}//...}}//关键流程:step2private void completePauseLocked(boolean resumeNext) {// 获取当前正在暂停的 ActivityRecordActivityRecord prev = mPausingActivity;if (prev != null) {// 将 Activity 的状态设置为 PAUSEDprev.state = ActivityState.PAUSED;// 如果 Activity 正在结束,则调用 finishCurrentActivityLocked 方法完成结束操作if (prev.finishing) {prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);} else if (prev.app != null) { // 如果 Activity 关联的应用不为空// 如果 Activity 正在等待可见状态,则更新状态并从等待列表中移除if (prev.waitingVisible) {prev.waitingVisible = false;mStackSupervisor.mWaitingVisibleActivities.remove(prev);}// 如果需要销毁 Activity,则调用 destroyActivityLocked 方法if (prev.configDestroy) {destroyActivityLocked(prev, true, "pause-config");} else if (!hasVisibleBehindActivity()) { // 如果没有可见的后置 Activity// 将当前 Activity 添加到停止的 Activity 列表中mStackSupervisor.mStoppingActivities.add(prev);// 根据条件决定是否调度空闲状态if (mStackSupervisor.mStoppingActivities.size() > 3 ||prev.frontOfTask && mTaskHistory.size() <= 1) {mStackSupervisor.scheduleIdleLocked();} else {mStackSupervisor.checkReadyForSleepLocked();}}} else {prev = null;}// 清空正在暂停的 ActivitymPausingActivity = null;}// 如果需要恢复下一个 Activityif (resumeNext) {final ActivityStack topStack = mStackSupervisor.getFocusedStack();// 如果服务没有进入休眠或关闭状态,恢复顶层 Activityif (!mService.isSleepingOrShuttingDown()) {mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);} else {// 检查是否准备好进入休眠状态mStackSupervisor.checkReadyForSleepLocked();ActivityRecord top = topStack.topRunningActivityLocked(null);// 如果顶层 Activity 为空或与当前暂停的 Activity 不同,恢复顶层 Activityif (top == null || (prev != null && top != prev)) {mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);}}}// 如果 prev 不为空,恢复按键分发if (prev != null) {prev.resumeKeyDispatchingLocked();//电池信息统计}// 通知任务栈发生了变化mService.notifyTaskStackChangedLocked();}

completePauseLocked 方法用于完成 Activity 的pause操作。它首先更新 Activity 的状态并处理与应用相关的各种情况,包括销毁、停止和恢复下一个 Activity。方法还处理 CPU 使用情况的更新,并在 Activity 状态变化时通知系统。这个方法确保了 Activity 在暂停时能够正确地保存状态和资源,同时为下一个 Activity 的恢复做好准备。

但是注意,这里涉及老activity的pause和新activity的resume操作,相信第一次看的伙伴并不容易理解,因此这里使用一个案例来帮忙理解。

1.3 场景案例解读completePauseLocked

这里使用一个场景案例来解读所谓的completePauseLocked在逻辑上到底是干了啥?便于理解。当使用 am 命令从 Launcher 界面启动一个 Settings Activity 时,Android 系统会经历以下步骤。每个步骤详细解读如下。

1.3.1 启动 Settings Activity:

系统通过 ActivityManagerService 的 startActivity() 方法启动新的 Settings Activity。

ActivityManagerService 负责协调启动过程,包括创建新的 Activity 记录(ActivityRecord)和调度启动。

1.3.2 Launcher 的 onPause() 调用:

在新的 Settings Activity 变得可见之前,当前的 Launcher Activity 需要进入暂停(paused)状态。

ActivityManagerService 会通知 Launcher Activity 调用它的 onPause() 生命周期方法。

这是通过 completePauseLocked() 方法完成的,该方法会更新 Launcher Activity 的状态为 PAUSED 并执行相关的暂停操作。

1.3.3 Settings Activity 的 onCreate() 和 onStart() 调用:

随着新的 Settings Activity 被创建,它的 onCreate() 和 onStart() 生命周期方法会被调用。

这些方法负责初始化 Activity,设置 UI,以及准备显示内容。

1.3.4 Settings Activity 的 onResume() 调用:

一旦 Settings Activity 准备好显示,它的 onResume() 方法会被调用。

onResume() 方法标志着 Activity 变得可见并开始与用户交互。

1.3.5 completePauseLocked() 中的逻辑:

如果 completePauseLocked() 方法被调用,它会处理 Launcher Activity 的暂停逻辑。

这包括调用 Launcher Activity 的 onPause() 方法,更新系统状态,以及准备恢复下一个 Activity。

如果 resumeNext 参数为 true,completePauseLocked() 方法会请求 ActivityManagerService 恢复下一个 Activity,即 Settings Activity。

1.3.6 Settings Activity 的恢复:

在 Launcher Activity 暂停后,ActivityManagerService 会负责恢复 Settings Activity。

这涉及到调用 Settings Activity 的 onResume() 方法,使其成为前台 Activity。

总结来说,在这种场景下,completePauseLocked() 方法主要负责处理 Launcher Activity 的暂停逻辑,而 Settings Activity 的 onResume() 方法会在 Launcher Activity 暂停后被调用,以确保用户体验的连续性和响应性。这个过程是由 ActivityManagerService 协调。

2 stopActivityLocked方法(onStop处理)

2.1 找到stopActivityLocked调用的入口Idler

stopActivityLocked藏的比较深,接下来我们从handleResumeActivity开始。想更多了解可参考文

章:Android Framework AMS(05)startActivity分析-2(ActivityThread启动到Activity拉起),文中

2.2.2 对handleResumeActivity方法有详细的解读,本次我们关注点不同,handleResumeActivity

关键代码解读如下:

//ActivityThreadfinal void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {unscheduleGcIdler();  // 取消垃圾回收的定时器,准备恢复 ActivitymSomeActivitiesChanged = true;  // 标记有 Activity 状态改变// 关键方法:resume Activity 的操作ActivityClientRecord r = performResumeActivity(token, clearHide);  if (r != null) {//...if (!r.onlyLocalRequest) {r.nextIdle = mNewActivities;  // 设置下一个空闲的 ActivitymNewActivities = r;  // 设置新的 ActivityLooper.myQueue().addIdleHandler(new Idler());  // 添加空闲处理器}r.onlyLocalRequest = false;  // 清除本地请求标志if (reallyResume) {try {ActivityManagerNative.getDefault().activityResumed(token);  // 通知 AMS Activity 已resume} catch (RemoteException ex) {}}} else {//...}}

这里我们主要关注一句话:

Looper.myQueue().addIdleHandler(new Idler());

接下来我们对这句话进行详细解读:

  • Looper.myQueue():获取当前线程的消息队列。在 Android 中,每个线程都有自己的消息队列,而主线程的消息队列是处理 UI 更新和生命周期回调的核心。Looper 对象与消息队列关联,负责循环处理队列中的消息。
  • addIdleHandler():向消息队列添加一个空闲处理器(IdleHandler)。空闲处理器是一种特殊的回调接口,它在消息队列中没有消息时被调用,即在消息队列空闲时触发。
  • new Idler():创建一个新的 Idler 实例。Idler 是 IdleHandler 接口的一个实现,它定义了在消息队列空闲时执行的操作。

这行代码的设计目的是为了在主线程空闲时进行垃圾回收和其他优化操作。通过这种方式,系统可以在不影响 UI 性能的情况下,做一些事情,比如:提高资源利用率,减少内存泄漏,优化电池使用,并提供更平滑的用户体验。这是 Android 系统中一个重要的性能优化机制。

当消息队列中没有消息时Idler 会被调用,更具体地说,IdleHandler 的 queueIdle 方法将会被调用。接下里我们看该方法的实现,代码如下:

//ActivityThread//Idler@Overridepublic final boolean queueIdle() {//activity列表含义,最近被启动但还没有报告为空闲(idle)的 Activity 实例ActivityClientRecord a = mNewActivities;boolean stopProfiling = false;//性能相关处理//...if (a != null) { // 如果存在新的 Activity 记录// 清空 mNewActivities 链表,准备处理这些 ActivitymNewActivities = null;IActivityManager am = ActivityManagerNative.getDefault();ActivityClientRecord prev;do {// 如果 Activity 存在且没有finishif (a.activity != null && !a.activity.mFinished) {try {// 通知 AMS,Activity 已经空闲am.activityIdle(a.token, a.createdConfig, stopProfiling);// 清空创建配置,表示已经处理a.createdConfig = null;} catch (RemoteException ex) {//...}}// 记录当前 Activity 记录,然后移动到下一个prev = a;a = a.nextIdle;// 断开当前记录的下一个引用,避免内存泄漏prev.nextIdle = null;} while (a != null);}//...ensureJitEnabled();// 返回false 表示不再需要这个IdleHandler,将其从消息队列中移除return false;}

这个方法主要用于处理消息队列空闲时的一些操作,这组 ActivityClientRecord 列表代表了那些需要进一步处理或状态更新的 Activity 实例。它们在消息队列空闲时被处理,通知 AMS 某个 Activity 已经空闲。这些操作都是在 UI 线程没有其他工作时完成的,这样可以确保不会影响用户界面的响应性。activityIdle代码实现如下:

//ActivityManagerService@Overridepublic final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {final long origId = Binder.clearCallingIdentity();synchronized (this) {ActivityStack stack = ActivityRecord.getStackLocked(token);if (stack != null) {ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token, false, config);//性能相关处理//...}}Binder.restoreCallingIdentity(origId);}

继续分析ActivityStackSupervisor.activityIdleInternalLocked方法的实现,代码如下:

//ActivityStackSupervisorfinal ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,Configuration config) {ArrayList<ActivityRecord> stops = null;ArrayList<ActivityRecord> finishes = null;ArrayList<UserStartedState> startingUsers = null;int NS = 0; // 停止activity的计数int NF = 0; // 结束activity的计数boolean booting = false; // 标记系统是否正在启动boolean activityRemoved = false; // 标记是否有activity被移除// 根据 token 获取对应的 ActivityRecord 对象ActivityRecord r = ActivityRecord.forToken(token);if (r != null) {mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);r.finishLaunchTickingLocked();// 如果是因为超时导致的空闲,报告activity已启动// 针对stop的分析,这里fromTimeout=falseif (fromTimeout) {reportActivityLaunchedLocked(fromTimeout, r, -1, -1);}if (config != null) {r.configuration = config;}r.idle = true;// 标记 Activity 为空闲状态// 如果 Activity 位于前台栈或者是因为超时,检查是否完成启动if (isFrontStack(r.task.stack) || fromTimeout) {booting = checkFinishBootingLocked();}}// 如果所有恢复的activity都处于空闲状态,调度应用程序的垃圾回收if (allResumedActivitiesIdle()) {if (r != null) {mService.scheduleAppGcsLocked();}// 如果有activity正在启动并且被暂停,移除相关的消息并释放if (mLaunchingActivity.isHeld()) {mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);//...mLaunchingActivity.release();}// 确保activity可见ensureActivitiesVisibleLocked(null, 0);}// 处理所有标记为停止的activitystops = processStoppingActivitiesLocked(true);NS = stops != null ? stops.size() : 0;// 如果有等待完成的activity,将它们添加到列表中并清空原列表if ((NF=mFinishingActivities.size()) > 0) {finishes = new ArrayList<ActivityRecord>(mFinishingActivities);mFinishingActivities.clear();}// 如果有正在启动的用户,将它们添加到列表中并清空原列表if (mStartingUsers.size() > 0) {startingUsers = new ArrayList<UserStartedState>(mStartingUsers);mStartingUsers.clear();}// 停止所有标记为停止的activityfor (int i = 0; i < NS; i++) {r = stops.get(i);final ActivityStack stack = r.task.stack;if (r.finishing) {// 如果activity正在完成,立即结束它stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);} else {//关键方法:stop activity操作stack.stopActivityLocked(r);}}// 完成所有标记为结束的activityfor (int i = 0; i < NF; i++) {r = finishes.get(i);// 如果activity被移除,标记 activityRemoved 为 trueactivityRemoved |= r.task.stack.destroyActivityLocked(r, true, "finish-idle");}// 如果系统不在启动过程中,完成用户启动if (!booting) {if (startingUsers != null) {for (int i = 0; i < startingUsers.size(); i++) {mService.finishUserSwitch(startingUsers.get(i));}}if (mStartingBackgroundUsers.size() > 0) {startingUsers = new ArrayList<UserStartedState>(mStartingBackgroundUsers);mStartingBackgroundUsers.clear();for (int i = 0; i < startingUsers.size(); i++) {mService.finishUserBoot(startingUsers.get(i));}}}// 修剪应用程序,释放无用资源mService.trimApplications();// 如果有activity被移除,恢复顶层activityif (activityRemoved) {resumeTopActivitiesLocked();}return r;}

至此,终于看到stopActivityLocked操作了。接下来我们以分析此方法为主。

2.2 stopActivityLocked方法解读(onStop处理)

stopActivityLocked方法的实现,代码如下:

//ActivityStackfinal void stopActivityLocked(ActivityRecord r) {// 如果 Activity 在其 intent 或 activity info 中被标记为没有历史记录(即不在后退栈中出现)if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {// 如果 Activity 还没有结束if (!r.finishing) {// 如果系统没有在睡眠状态if (!mService.isSleeping()) {// 请求结束这个 Activity,并传递一个取消的结果码requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, "no-history", false);}}}// 如果 Activity 的应用和线程不为空if (r.app != null && r.app.thread != null) {// 调整焦点 ActivityadjustFocusedActivityLocked(r, "stopActivity");// 恢复分派按键事件r.resumeKeyDispatchingLocked();try {// 重置 Activity 的 stopped 状态r.stopped = false;// 更新 Activity 的状态为 STOPPINGr.state = ActivityState.STOPPING;// 如果 Activity 不可见,通知窗口管理器if (!r.visible) {mWindowManager.setAppVisibility(r.appToken, false);}// 关键方法:通过应用线程请求停止 Activityr.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);// 如果系统正在睡眠或关闭,设置 Activity 为睡眠状态if (mService.isSleepingOrShuttingDown()) {r.setSleeping(true);}// 获取一个消息对象,并将其发送到消息队列,如果 Activity 停止操作超时,将处理该消息Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);} catch (Exception e) {// 异常处理(省略)}}}

stopActivityLocked 负责停止一个 Activity。它首先检查 Activity 是否被标记为没有历史记录,如果是,并且 Activity 还没有结束,且系统不在睡眠状态,它会请求结束这个 Activity。接下来,如果 Activity 的应用和线程不为空,它会调整焦点 Activity,恢复按键分派,更新 Activity 的状态为 STOPPING,并请求应用线程停止这个 Activity,这里较为关键。如果系统正在睡眠或关闭,它会设置 Activity 为睡眠状态。最后,它会发送一个延迟消息,用于处理停止操作的超时情况。

接下来我们关注关键方法ActivityThread.scheduleStopActivity的实现,代码如下:

//ActivityThread//ApplicationThreadpublic final void scheduleStopActivity(IBinder token, boolean showWindow,int configChanges) {sendMessage(showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,token, 0, configChanges);}//...//Handler消息处理private class H extends Handler {public void handleMessage(Message msg) {switch (msg.what) {//...case STOP_ACTIVITY_SHOW:handleStopActivity((IBinder)msg.obj, true, msg.arg2);break;//...}}//...}//...private void handleStopActivity(IBinder token, boolean show, int configChanges) {ActivityClientRecord r = mActivities.get(token);r.activity.mConfigChangeFlags |= configChanges;StopInfo info = new StopInfo();// 执行停止 Activity 的内部操作performStopActivityInner(r, info, show, true);// 更新 Activity 的可见性状态updateVisibility(r, show);//...// 安排在 UI 线程上告诉 Activity Manager 我们已经停止了 Activity// 我们不是立即这样做,因为我们希望在通知 Activity Manager 之前,// 有机会完成任何其他挂起的工作(特别是内存修剪请求),然后才能让应用完全进入后台info.activity = r;info.state = r.state;info.persistentState = r.persistentState;mH.post(info);mSomeActivitiesChanged = true; // 标记有 Activity 状态改变}

这里继续分析performStopActivityInner方法的实现,代码如下:

//ActivityThreadprivate void performStopActivityInner(ActivityClientRecord r,StopInfo info, boolean keepShown, boolean saveState) {if (r != null) {//...// 如果 Activity 没有完成(即没有调用过 finish()),并且需要保存状态if (!r.activity.mFinished && saveState) {// 如果 Activity 的状态对象为空,调用 onSaveInstanceState() 方法来保存状态if (r.state == null) {callCallActivityOnSaveInstanceState(r);}}// 如果 Activity 不需要保持显示状态if (!keepShown) {try {// 调用 Activity 的 performStop() 方法来执行停止操作r.activity.performStop();} catch (Exception e) {// ...}r.stopped = true;// 标记 Activity 为已停止状态}r.paused = true;// 标记 Activity 为已暂停状态}}

performStopActivityInner 负责执行 Activity 的停止操作。它首先检查 Activity 是否需要保持显示状态。如果不需要,并且 Activity 之前没有被停止过,它会执行停止操作。如果需要保存状态,它会调用 onSaveInstanceState() 方法来保存 Activity 的状态。最后,它调用 Activity 的performStop() 方法来执行实际的停止操作,并更新 Activity 的状态为已停止和已暂停。performStop方法实现,代码如下:

//Activityfinal void performStop() {// 标记不再需要报告完全绘制状态mDoReportFullyDrawn = false;// 如果加载器已经开始,现在需要停止它们if (mLoadersStarted) {mLoadersStarted = false; // 标记加载器已停止// 如果有加载器管理器,根据配置更改情况执行停止或保留操作if (mLoaderManager != null) {if (!mChangingConfigurations) {mLoaderManager.doStop(); // 停止加载器} else {mLoaderManager.doRetain(); // 保留加载器}}}// 如果 Activity 之前没有被停止过if (!mStopped) {// 如果有窗口对象,关闭所有面板if (mWindow != null) {mWindow.closeAllPanels();}// 如果 Activity 有 token 且没有父 Activity,通知窗口管理器该 Activity 已停止if (mToken != null && mParent == null) {WindowManagerGlobal.getInstance().setStoppedState(mToken, true);}// 分发 Fragment 的停止事件mFragments.dispatchStop();// 标记未调用 onStop()mCalled = false;//关键方法:该方法间接调用 Activity 的 onStop() 方法mInstrumentation.callActivityOnStop(this);//光标处理相关//...mStopped = true;// 标记 Activity 为已停止状态}mResumed = false;// 标记 Activity 不再处于 resume 状态}

performStop() 方法执行了 onStop() 生命周期方法之后的操作,包括停止 Loader,关闭窗口面板,更新 Fragment 的状态,释放数据库和光标资源,以及更新 Activity 的状态。这个方法确保了在 Activity 停止时,所有资源都被正确管理和释放,以避免内存泄漏和其他资源问题。此外,它还确保了 onStop() 方法被正确调用,如果没有,会抛出异常。最后更新了 Activity 的状态,以反映它不再处于 resume 状态。

至此,调用到activity的onStop方法了(mInstrumentation.callActivityOnStop)。有了onPause和onStop的分析方法,感兴趣的伙伴可以自行分析下onDestroy的流程。这里不再编写该部分。

3 超时设计的解读

这里的超时的设计以Activity的onStop超时处理为例。即2.2 中stopActivityLocked方法为例,解读下onStop的超时处理流程,整理后相关代码如下:

//ActivityStackfinal void stopActivityLocked(ActivityRecord r) {//...// 如果 Activity 的应用和线程不为空if (r.app != null && r.app.thread != null) {//...try {//...// 关键方法:通过应用线程请求停止 Activityr.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);//...// 获取一个消息对象,并将其发送到消息队列,如果 Activity 停止操作超时,将处理该消息Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);} catch (Exception e) {// 异常处理(省略)}}}

可以看到执行scheduleStopActivity后开始用handler发送延迟消息。注意:这里是不管是否延迟都会发消息。那么消息是在哪里处理的呢?

我们以scheduleStopActivity为入口进行分析。这里scheduleStopActivity通过handler发送消息,最终由handleStopActivity来处理,我们就从handleStopActivity这个方法开始分析,代码整理后,关键代码如下:

//ActivityThreadprivate void handleStopActivity(IBinder token, boolean show, int configChanges) {ActivityClientRecord r = mActivities.get(token);r.activity.mConfigChangeFlags |= configChanges;StopInfo info = new StopInfo();performStopActivityInner(r, info, show, true);//...updateVisibility(r, show);//...//这里开始通过post执行info的run方法info.activity = r;info.state = r.state;info.persistentState = r.persistentState;mH.post(info);mSomeActivitiesChanged = true;}

这里主要关注StopInfo的实现及run方法,因为post会导致run的调用,StopInfo代码如下:

    private static class StopInfo implements Runnable {ActivityClientRecord activity;Bundle state;PersistableBundle persistentState;CharSequence description;@Override public void run() {try {ActivityManagerNative.getDefault().activityStopped(activity.token, state, persistentState, description);} catch (RemoteException ex) {}}}

继续分析AMS的关键方法activityStopped的实现,代码如下:


//ActivityManagerService@Overridepublic final void activityStopped(IBinder token, Bundle icicle,PersistableBundle persistentState, CharSequence description) {//...final long origId = Binder.clearCallingIdentity();synchronized (this) {ActivityRecord r = ActivityRecord.isInStackLocked(token);if (r != null) {r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);}}trimApplications();Binder.restoreCallingIdentity(origId);}

继续分析这里的关键方法activityStoppedLocked的实现,整理关键代码内容分析,代码如下:

//ActivityStackfinal void activityStoppedLocked(ActivityRecord r, Bundle icicle,PersistableBundle persistentState, CharSequence description) {if (r.state != ActivityState.STOPPING) {Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);mHandler.removeMessages(STOP_TIMEOUT_MSG, r);return;}//...}

如果一切正常,那么最后会通过AMS,在ActivityStack的activityStoppedLocked中将这个超时消息移除。也就是正常情况下,只要不超过这个超时的时间,都会正常运行;出现超时的异常情况会导致延迟消息未取消而正常发送,导致异常处理的流程。

以上是以onStop的流程未基础进行分析,其他的onCreate、onStart、onResume、onPause等也是按照类似方式来处理超时的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/454073.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第 2 章 ROS通信机制

机器人是一种高度复杂的系统性实现&#xff0c;在机器人上可能集成各种传感器(雷达、摄像头、GPS...)以及运动控制实现&#xff0c;为了解耦合&#xff0c;在ROS中每一个功能点都是一个单独的进程&#xff0c;每一个进程都是独立运行的。更确切的讲&#xff0c;ROS是进程&#…

关于Linux自带的python2.6.6升级到2.7.5版本步骤详解

CentOS 6 系统默认 Python 版本是:2.6.6 平时在使用中遇到很多的库要求是 2.7.x 版本的库。比如使用UFR升级启动脚本用python2.6.6的版本启动状态检测报错: 第一步:安装相关的编译依赖包: [root@testhost250 ~]# sudo yum install -y gcc [root@testhost250 ~]# sudo yum …

使用JMeter录制元件来录制HTTPS下的脚本

1.给测试计划添加一个线程组 2.给线程组添加【HTTP请求默认值】 3.配置【HTTP请求默认值】下面的【web服务器】参数&#xff0c;这里举例为www.baidu.com 4.在测试计划(注意是测试计划哦)上添加【非测试元件】->【HPPT(S)测试脚本记录器】 5.记下默认端口号&#xff0c;此处…

浏览器控制的无线开关

esp32-c3 作为HTTP server 控制led 灯。服务器注册两个uri 。一个"/open" 控制开&#xff0c;一个"/close"控制关。下一步再用一片c3作为客户端&#xff0c;运行http client 发送/open. /Close 模拟浏览器&#xff0c;控制led. 其实只要用手机或pc或平…

Apache Lucene 10 已发布!Lucene 硬件效率改进及其他改进

作者&#xff1a;来自 Elastic Adrien Grand Apache Lucene 10 刚刚发布&#xff0c;重点关注硬件效率&#xff01;查看主要版本亮点。 Apache Lucene 10 终于发布了&#xff01;自 Lucene 9.0&#xff08;于 2021 年 12 月发布&#xff0c;距今已有近 3 年&#xff09;以来&a…

C++20中头文件source_location的使用

<source_location>是C20中新增加的头文件&#xff0c;此头文件是utility库的一部分。 主要内容为类std::source_location&#xff1a;表示有关源代码的某些信息&#xff0c;例如文件名(__FILE__)、行号(__LINE__)和函数名(__func__)。 以下为测试代码&#xff1a; names…

Redis 高可用:从主从到集群的全面解析

目录 一、主从复制 (基础)1. 同步复制a. 全量数据同步b. 增量数据同步c. 可能带来的数据不一致 2. 环形缓冲区a. 动态调整槽位 3. runid4. 主从复制解决单点故障a. 单点故障b. 可用性问题 5. 注意事项a. Replica 主动向 Master 建立连接b. Replica 主动向 Master 拉取数据 二、…

Vue+TypeScript+SpringBoot的WebSocket基础教学

成品图&#xff1a; 对WebSocket的理解&#xff08;在使用之前建议先了解Tcp&#xff0c;三次握手&#xff0c;四次挥手 &#xff09;&#xff1a; 首先页面与WebSocket建立连接、向WebSocket发送信息、后端WebSocket向所有连接上WebSoket的客户端发送当前信息。 推荐浏览网站…

【网络原理】HTTP协议

目录 前言 一.什么是HTTP HTTP报文格式 HTTP的请求格式 1.首行 2.请求头&#xff08;header&#xff09; 3.空行 4.正文&#xff08;body&#xff09; HTTP的响应格式 1.首行 2.响应头 3.空行 4.正文&#xff08;body&#xff09; 首行中的方法 GET和POST的区别 …

linux中级wed服务器(https搭建加密服务器)

一。非对称加密算法&#xff1a; 公钥&#xff1a;公共密钥&#xff0c;开放 私钥&#xff1a;私有密钥&#xff0c;保密 1.发送方用自己的公钥加密&#xff0c;接受方用发送方的私钥解密&#xff1a;不可行 2.发送方用接受方的公钥加密&#xff0c;接受方用自己的私钥解密…

基于yolov10的驾驶员抽烟打电话安全带检测系统python源码+pytorch模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv10的驾驶员抽烟、打电话、安全带检测系统是一种先进的驾驶行为监测系统。该系统利用YOLOv10算法的高效性和准确性&#xff0c;实现对驾驶员行为的实时检测与识别。 YOLOv10是一种最新的实时物体检测模型&#xff0c;其通过深度学习技术&#xff0c;如卷…

spark统一内存模型 详解

Apache Spark 是一个用于大规模数据处理的分布式计算框架&#xff0c;它支持多种处理模型&#xff08;如批处理、流处理、SQL、机器学习等&#xff09;。为了高效地在分布式环境中处理这些多样化的工作负载&#xff0c;Spark 在 2.x 版本后引入了统一内存管理模型&#xff0c;以…

Mycat2安装配置

安装配置 安装 目前Mycat2下载地址已经不可访问&#xff0c;安装包可从参考资料[1]获取 下载后解压zip文件&#xff0c;将jar放在lib目录下 编辑配置文件 编辑conf文件夹下的prototypeDs.datasource.json 更改数据库相关信息 启动 windows环境下启动Mycat 以管理员身份运行…

Linux重点yum源配置

1.配置在线源 2.配置本地源 3.安装软件包 4.测试yum源配置 5.卸载软件包

Git 完整教程:版本管理、分支操作与远程仓库解析

文章目录 一、引言二、Git原理三、.git目录四、版本回退以及撤销修改五、Git远程控制1、创建仓库2、克隆/下载远程仓库到本地的方法3、本地仓库的修改推送到远程仓库4、拉取远程仓库的修改到本地仓库5、操作标签 六、Git分支1、分支操作&#xff08;创建、删除、合并&#xff0…

九种排序,一次满足

我们在算法题进行练习提升时&#xff0c;经常会看到题目要求数据从大到小输出&#xff0c;从小到大输出&#xff0c;前一半从小到大输出&#xff0c;后一半从大到小输出等&#xff0c;那么这时候就需要用到排序算法&#xff0c;通过排序算法将数据按照一定的顺序进行排序。本文…

排序02 Multi-gate Mixture-of-Experts (MMoE)

MMoE: 不一定适合业务场景 输入向量&#xff08;包含四种特征&#xff09;到三个神经网络&#xff08;专家&#xff09;&#xff0c;不共享参数。实践中超参数专家神经网络个数需要调&#xff0c;会尝试4个或者8个专家。 左边另一个神经网络softmax输出的向量&#xff0c;三个…

element-plus 官方表格排序问题

element-plus 官方API 默认表格排序存在问题&#xff0c;一个list 被多组排序 修改后&#xff1a; 注意点&#xff1a; 这里一定要使用 sortable"custom"&#xff0c;自定义 sort-change 方法 使用 sortable true 的情况排序会冲突&#xff0c;出现莫名奇妙的问题…

Oracle SQL练习题,从小白到入门 - 上

从事DBA以来&#xff0c;越来越认识到自己SQL水平不足&#xff0c;想想sql语句还停留在大二寒假学习的黑马的Mysql《Mysql 十天精通》基础篇进阶篇&#xff0c;将近100集一天就学完了&#xff0c;黑马yyds。 再后来&#xff0c;做项目用Spring的MyBatis是真的香&#xff0c;练…

string类的学习(上)

string类与我们再C语言中接触到的字符串数据相似&#xff0c;但是做出了一些重大的提升&#xff0c;封装为类&#xff0c;实现了总多的接口&#xff0c;丰富了其功能&#xff0c;为简化了字符串的使用&#xff0c;那现在我们就开始深入学习string类吧。 1.什么事string类 C语言…