自 2025 年 3 月 27 日起,我们建议您使用 android-latest-release
而非 aosp-main
构建 AOSP 并为其做出贡献。如需了解详情,请参阅 AOSP 的变更。
多项恢复
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
在 Android 9(及更低版本)中,应用会在以下情况下进入 PAUSED
状态:
- 一项新的半透明 Activity 在应用的上层启动,同时应用仍然可见(因此并未停止)。
- 该 activity 失去了焦点,但没有被遮挡,可以与用户进行互动。例如,在多窗口模式下,一些 activity 处于可见状态,并可同时接收触控输入。
这些情况的不同之处在于应用必须执行的暂停次数,但无法在应用级别进行区分。
在 Android 10 中,可见堆栈中所有可设置为焦点的顶层 Activity 都处于 RESUMED
状态。对于使用 onPause()
(而非 onStop()
)来停止刷新界面及与用户互动的应用而言,这样可提高与多窗口模式和多屏幕 (MD) 模式的兼容性。也就是说:
- 在分屏模式下,两个 activity 都处于 RESUMED 状态。
- 在自由格式的窗口模式下,所有可见的顶层 activity 都处于 RESUMED 状态。
- 多个屏幕上的 Activity 可以同时处于 RESUMED 状态。

图 1. 可折叠设备上的多项恢复

图 2. 在桌面模式下的多项恢复
当 activity 无法设置为焦点或被部分遮挡时(示例如下),它们可以处于 PAUSED
状态:
- 在已最小化的分屏(启动器在侧面)模式下,顶层 activity 不处于已恢复状态,因为它无法设置为焦点。
- 在画中画模式下,activity 不处于已恢复状态,因为它无法设置为焦点。
- 当 activity 被同一堆栈中的其他透明 activity 覆盖时。
在此方式下,对应用而言,activity 仅在 RESUMED
状态下才能接收来自用户的输入。在 Android 10 之前,Activity 也可以在 PAUSED
状态下接收输入(例如,您可以试试在搭载 Android 9 的设备上同时轻触分屏模式下的两个 Activity)。
为了保留之前 Android 版本的“已恢复”信号(并告知应用应在何时获取对独占资源或单例资源的访问权),Android 10 新增了一个回调:
Activity#onTopResumedActivityChanged(boolean onTop)
调用后,此回调将在 Activity#onResume()
和 Activity#onPause()
之间实际得到调用。此回调并非必需且可以跳过,因此,Activity 可以从 RESUMED
变为 PAUSED
状态,而不会处于系统的最顶层,如在多窗口模式下。由于此回调并非必需,因此它不是 activity 生命周期的一部分,应很少使用。
上一个在顶层处于 RESUMED 状态的 activity 先接收 onTopResumedActivity(false)
并完成其执行过程,然后下一个在顶层处于 RESUMED 状态的 activity 才会接收 onTopResumedActivity(true)
,除非上一个 activity 在处理该方法调用时花费了过长时间并达到了 500ms 超时。
兼容性
如要在实现多项恢复时保持兼容性,请考虑以下解决方案。
在一个应用进程中启动多个处于已恢复状态的 activity
- 问题:在 Android 9 及更低版本中,系统同时只允许一个 activity 处于 RESUMED 状态。多个 activity 执行任何转换时,都需要先暂停一个 activity,然后再恢复另一个 activity。一些应用和框架(例如 Flutter,或 Android 的 LocalActivityManager)会利用此行为方式,并在单例中存储已恢复的 Activity 的相关状态。
- 解决方案:在 Android 9 及更低版本中,如果同一进程中的两个 Activity 都要进行恢复,系统仅会恢复在 Z 轴顺序中较高的 Activity。以 Android 10 为目标平台的应用可支持同时恢复多个 Activity。
同时提供相机访问权限
- 问题:这些问题在 Android 9 及更低版本中也存在。例如,在画中画模式下,处于已恢复状态的全屏 activity 可能会丢失相机焦点,而在顶层处于已恢复状态的 activity 则会获取相机焦点。随着多窗口和多屏幕模式的广泛采用,这种情况越来越多。
- 由于对
RESUME
状态做出的更改,应用即使处于 RESUMED 状态,也可能与相机断开连接。为了解决这个问题,应用必须处理与相机断开连接的问题,避免出现崩溃。连接断开后,应用会收到断开连接的回调,并且所有对相应 API 的调用都会开始抛出 CameraAccessException
。
resizeableActivity=false
并不能保证应用获得对相机的专属访问权限,因为系统可能会在其他屏幕上打开其他用到相机的应用。
- 解决方案:开发者应该指明应用与相机断开连接后应执行的逻辑。如果某个应用与相机断开连接,它应监视相机可用性回调,以尝试重新连接并继续使用相机。除了现有的
CameraManager#AvailabilityCallback#onCameraAvailable()
回调之外,Android 10 还添加了 CameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged()
,它涵盖了焦点(以及相机优先使用权)在处于 RESUMED 状态的多个 Activity 之间切换的情况。应用开发者应同时使用这两个回调来确定尝试访问相机的适当时机。
多项恢复
在 Android 10 中,activity 生命周期状态由可见性和 Z 轴顺序决定。为确保在 activity 的可见性更新后具有正确的状态并评估哪个生命周期状态适用,请从不同位置调用 ActivityRecord#makeActiveIfNeeded()
方法。在 Android 10 中,“活跃”意味着应用处于 RESUMED
或 PAUSED
状态,且仅适用于这两种情况。
在 Android 10 中,恢复 Activity 的过程将在每个堆栈中(而不是系统中的单个位置)单独进行跟踪。这是因为多窗口模式下可以同时执行多个 activity 转换。如需了解详情,请参阅 ActivityStack#mInResumeTopActivity
。
在顶层处于已恢复状态的 activity 回调
在执行可能导致顶层 activity 发生更改的操作(例如启动 activity、恢复或更改 Z 轴顺序)之后,系统将调用 ActivityStackSupervisor#updateTopResumedActivityIfNeeded()
。此方法会检查在顶层处于已恢复状态的 activity 是否已更改,并在需要时执行更新。如果上一个在顶层处于已恢复状态的 activity 尚未释放这一状态,系统会向其发送一条告知其失去该状态的消息,并在服务器端安排一项超时操作 (ActivityStackSupervisor#scheduleTopResumedStateLossTimeout()
)。在该 activity 释放这一状态或发生超时后,系统会将该状态授予下一个 activity。用法如下:
ActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()
Android 10 新增了一项 TopResumedActivityChangeItem
事务,该事务用于向客户端报告在顶层处于已恢复状态的更改,并利用了 Android 9 中的 ActivityLifecycler
架构。
该状态的相关信息存储在客户端,每次 Activity 转换为 RESUMED
或 PAUSED
时,系统还会检查是否应该调用 onTopResumedActivityChanged()
回调。这可以在服务器和客户端之间就生命周期状态和“在顶层处于已恢复状态”这一状态进行通信时实现某些分离。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-03-11。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-03-11。"],[],[],null,["# Multi-resume\n\nIn Android 9 (and lower), apps were entered into the `PAUSED` state when:\n\n- A new, translucent activity launched on top of the app, while the app was still visible (and, therefore, wasn't stopped).\n- The activity lost focus, but was unobscured and could be interacted with by the user. For example, in multi-window mode, a number of activities can be visible and receive touch input simultaneously.\n\nThese situations differ in the amount of *pausing* an app must do but can't be\ndistinguished at the app level.\n\nIn Android 10, all top-focusable activities in visible stacks reside in\nthe `RESUMED` state. This improves compatibility with\n[Multi-Window](/docs/core/display/multi-window) and MD modes for apps that use\n`onPause()` instead of `onStop()` to stop refreshing the UI and interacting\nwith the user. This means:\n\n- Both activities in split-screen are resumed.\n- All top-visible activities in free-form windowing mode are resumed.\n- Activities on multiple screens can be resumed at the same time.\n\n**Figure 1.** Multi-resume on a foldable device\n\n**Figure 2.** Multi-resume in desktop mode\n\nActivities can reside in the `PAUSED` state when they cannot be focused upon or are\npartially occluded, such as:\n\n- In a minimized split-screen (with launcher on side), the top activity isn't resumed because it's not focusable.\n- In a picture-in-picture mode, the activity isn't resumed because it's not focusable.\n- When activities are covered by other transparent activities in the same stack.\n\nThis approach indicates to apps that an activity can receive input from a\nuser only in the `RESUMED` state. Before Android 10,\nactivities could also receive input in the `PAUSED` state (for example, try touching\nboth activities in split-screen simultaneously on a device running Android 9).\n\nTo preserve the *resumed* signal from previous Android releases (and\nto communicate when apps should obtain access to exclusive-access or singleton\nresources), Android 10 includes a new callback: \n\n```text\nActivity#onTopResumedActivityChanged(boolean onTop)\n```\n\nWhen invoked, this callback is called between `Activity#onResume()`\nand `Activity#onPause()`. This callback is optional and can be skipped,\nso an activity can go from a `RESUMED` to a `PAUSED` state\nwithout becoming the topmost in the system. For example, in multi-window mode.\nBecause this callback is optional, it's not part of the [Activity\nLifecycle](https://developer.android.com/guide/components/activities/activity-lifecycle) and should be rarely used.\n\nThe previous top-resumed activity receives and finishes execution of\n`onTopResumedActivity(false)` before the next top-resumed activity\nreceives `onTopResumedActivity(true)` unless the previous activity\ntakes too much time to handle the method call and hits the 500 ms timeout.\n\nCompatibility\n-------------\n\nTo maintain compatibility when implementing multi-resume, consider these\nsolutions.\n\n### Multiple resumed activities in one app process\n\n- Issue. In Android 9 and lower, only one activity in the system is resumed at a time. All transitions between activities involve pausing an activity before resuming another. Some apps and frameworks (such as Flutter, or Android's LocalActivityManager) use this fact, and store state about the resumed activity in singletons.\n- Solution. In Android 9 and lower, if two activities from the same process are both resumed, the system only resumes the activity that's higher in Z-order. Apps targeting Android 10 can support multiple activities being resumed at the same time.\n\n### Simultaneous camera access\n\n- **Issues** . These issues are also present in Android 9 and lower. For example, a fullscreen and resumed activity can lose camera focus to a paused activity on top in picture-in-picture mode but become more exposed with wider adoption of multi-window and multi-display modes.\n - Due to changes made to the `RESUME` state, apps may be disconnected from the camera *even while resumed* . To address this, apps must handle a camera disconnect without crashing. When disconnected, apps get a disconnected callback and all calls into the API start throwing `CameraAccessException`.\n - `resizeableActivity=false` isn't a guarantee of exclusive camera access, because other apps using the camera can be opened on other displays.\n- **Solutions.** Developers should include logic for when an app is disconnected from the camera. If an app is disconnected from the camera, it should watch camera availability callbacks to try to reconnect and continue camera use. In addition to the existing `CameraManager#AvailabilityCallback#onCameraAvailable()` callback, Android 10 added `CameraManager#AvailabilityCallback#onCameraAccessPrioritiesChanged()`, which covers the case when focus (and camera priority) switches between several resumed activities. App developers should use both of these callbacks to determine a good time to try to get access to the camera.\n\n### Multi-resume\n\nIn Android 10, the activity lifecycle state is determined by visibility and\nZ-order. To ensure that the correct state after visibility updates on an\nactivity and evaluate which lifecycle state is applicable, invoke the\n`ActivityRecord#makeActiveIfNeeded()` method from different\nlocations. In Android 10, active means either `RESUMED` or\n`PAUSED` and works only in these two instances.\n\nIn Android 10, resuming an activity is separately tracked in each stack\ninstead of in the single location in the system. This is because several\nactivity transitions can be performed simultaneously in multi-window modes. For\ndetails, see `ActivityStack#mInResumeTopActivity`.\n\n### Top-resumed activity callback\n\nAfter actions that can result in a top activity change (such as activity\nlaunch, resuming, or Z-order change),\n`ActivityStackSupervisor#updateTopResumedActivityIfNeeded()` is invoked. This\nmethod checks if the topmost resumed activity changed and performs the update if\nneeded. If the previous top-resumed activity hasn't release the top-resumed\nstate, then a top-resumed-state-loss message is sent to it and a timeout is\nscheduled on the server side\n(`ActivityStackSupervisor#scheduleTopResumedStateLossTimeout()`).\nA report of the top-resumed state is sent to the next activity after the previous\none released the state, or when a timeout was hit (see usages of: \n\n```text\nActivityStackSupervisor#scheduleTopResumedActivityStateIfNeeded()\n```\n\nA new `TopResumedActivityChangeItem` transaction item was added\nto report top-resumed state changes to clients and leverages the\n`ActivityLifecycler` architecture from Android 9.\n\nThe top-resumed state is stored on the client side, and each time the\nactivity transitions to `RESUMED` or `PAUSED` it also\nchecks whether the `onTopResumedActivityChanged()` callback should be\ninvoked. This enables certain decoupling in the communication of lifecycle states\nand the top-resumed state between the server and client sides."]]