Android 10 (API 级别 29) 为可折叠设备和不同折叠模式增加更多支持
展开设备以提供更大的屏幕能够为用户带来积极影响:
- 屏幕更大通常意味着更身临其境的体验。
- 用户可以利用多窗口模式同时执行多项任务。
折叠和展开设备可以更改屏幕尺寸、密度或比例。这在 Android 开发中不是新问题。以下非折叠情况中已存在这样的问题:
- 手机:在竖屏和横屏模式之间切换。
- 在桌面模式中运行的 Chrome 操作系统:调整 Android 应用的大小。
- 具有多个或额外屏幕的设备。
本页面将介绍旨在确保应用可与各种可折叠设备机型顺畅配合使用的最佳实践。
您可能还需要阅读涉及可折叠设备支持的 Android 10 变更摘要。
应用连续性
在可折叠设备上运行时,应用可以自动从一个屏幕转换到另一个屏幕。为了提供出色的用户体验,请务必要确保当前任务能在转换后继续无缝执行。应用应在同一位置以相同状态恢复。请注意,可折叠设备能以多种方式折叠,例如向内或向外折叠:
系统会在转换时触发配置变更,因此应用应能妥善地保存界面状态和支持配置变更。
让应用大小可调
您应该确保应用能够在多窗口模式下运行,并且应用的大小可动态调整。设置 resizeableActivity=true
即可实现此目的。这可以为应用可能遇到的任何设备类型和环境(例如可折叠设备、桌面模式或自由窗口)提供最大兼容性。请在分屏模式下,或使用可折叠模拟器测试应用行为。
如果应用设置 resizeableActivity=false
,则会告知平台其不支持多窗口模式。系统可能仍会调整应用的大小或将其置于多窗口模式;但要实现兼容性,便需要对应用中的所有组件(包括应用的所有 Activity、Service 等)应用同一配置。在某些情况下,重大变更(例如,显示屏尺寸更改)可能会重启进程,而不会更改配置。
例如,以下 Activity 设置了 resizableActivity=false
以及 maxAspectRatio
。设备展开时,系统会将应用置于兼容模式,以此保持 Activity 配置、大小和宽高比。
如果未设置 resizeableActivity
,或将其设置为 true,系统会假定该应用完全支持多窗口并且可调整大小。
请注意,某些原始设备制造商 (OEM) 可能会实施一项功能,即每当 Activity 的显示区域发生更改时,都会在屏幕上添加一个小型重启图标。这为用户提供了在新配置中重启 Activity 的机会。
新的屏幕宽高比
Android 10 (API 级别 29) 或更高版本 支持更多种宽高比。对于可折叠设备而言,设备类型可以是超长、超薄的屏幕(例如屏幕宽高比为 21:9 的折叠设备),也可以是 1:1 的屏幕。
如要与尽可能多的设备兼容,您应该尽量多针对以下屏幕宽高比测试自己的应用:
如果无法支持上述某些高宽比,您可以使用 maxAspectRatio
(同之前一样)以及 minAspectRatio
来指明自己应用可以处理的最高宽高比和最低宽高比。如果屏幕宽高比超出这些限制,应用可能会进入兼容模式。
如果底部导航视图有五个图标,则可保证运行 Android 10 (API 级别 29) 或更高版本 的设备的触摸目标大小至少为 2 英寸。请参阅兼容性定义文档。
多窗口模式
大屏幕的好处之一是能够运行多个窗口。过去,在某些设备中并排放置两个应用的情况很常见。现在,技术取得长足发展,可支持三个或更多应用同时在一个屏幕上运行,并且相互之间还可以共享内容:
如果应用不能妥善支持多窗口模式,则可以设置 resizeableActivity=false
。如需了解详细信息,请参阅多窗口模式指南。
随着多窗口模式越来越常见,不妨考虑在应用中支持拖放功能。
多项恢复
在搭载 Android 9.0 及更低版本的设备上运行时,只有获得焦点的应用处于已恢复状态。任何其他可见 Activity 都处于已暂停状态。如果应用在处于暂停状态时关闭资源或停止播放内容,则可能会产生问题。
在 Android 10 中,此行为发生了变化,即当设备处于多窗口模式时,所有 Activity 都会保持已恢复状态。这称为多项恢复。请注意,如果顶部有透明 Activity,或者 Activity 不可成为焦点(例如,处于画中画模式),则相应 Activity 可能会处于已暂停状态。还有一种可能是,在特定时间内(例如,当打开抽屉式通知栏时)所有 Activity 都不具有焦点。OnStop
会继续照常工作。每当 Activity 从屏幕上移除时,系统都会调用它。
部分搭载 Android 9.0 的设备也提供多项恢复功能。如要在这些设备上选择启用多项恢复功能,您可以添加以下清单元数据:
<meta-data
android:name="android.allow_multiple_resumed_activities" android:value="true" />
如要验证给定设备是否支持此清单元数据,请参阅设备规范。
专属资源访问
为了帮助支持多项恢复功能,我们提供了一个新的生命周期回调 Activity#onTopResumedActivityChanged()
。
当 Activity 获得或失去顶部恢复 Activity 位置时,系统会调用此方法。当 Activity 使用共享的单用户资源(例如麦克风或摄像头)时,了解这一点至关重要。
protected void onTopResumedActivityChanged(boolean topResumed) {
if (topResumed) {
// Top resumed activity
// Can be a signal to re-acquire exclusive resources
} else {
// No longer the top resumed activity
}
}
请注意,应用可能会因其他多种原因丢失资源,例如移除共享硬件。
在任何情况下,应用都应妥善处理会影响可用资源的资源丢失事件和状态更改。
对于使用摄像头的应用,建议使用 CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged()
方法作为提示,提醒这可能是尝试访问摄像头的好时机。此方法在 Android 10 (API 级别 29) 或更高版本 中可用。
请记住,resizeableActivity=false
并不保证可以获取对摄像头的专属访问权限,因为其他使用摄像头的应用可能会在其他显示屏上打开。
多窗口模式下的摄像头。
应用不必在失去焦点时释放摄像头。例如,在用户与最顶层新聚焦的已恢复应用互动时,您可能希望继续保持摄像头预览。当应用不再是最顶层已恢复状态的应用时,其也可以继续运行摄像头,但必须妥善处理断开连接的情况。当最顶层的已恢复应用需要使用摄像头时,它可以打开摄像头,这时您的应用会失去对摄像头的访问权限。您的应用可以在重新获得焦点时重新打开摄像头。
应用收到 CameraDevice.StateCallback#onDisconnected()
回调后,对摄像头设备进行的后续调用将抛出 CameraAccessException
。
多显示屏
未来,可能会出现同时支持多个屏幕或显示屏的可折叠手机。处理此类配置的方式与开发者目前在 Chrome 操作系统上处理投影屏幕的方式类似。
Android 10 (API 级别 29) 或更高版本 支持辅助显示屏上的 Activity。如果 Activity 在具有多个显示屏的设备上运行,则用户可以将 Activity 从一个显示屏移到另一个显示屏。多项恢复功能也适用于多屏场景。多个 Activity 可以同时接收用户输入。
应用可以指定在启动或创建其他 Activity 时它应该在哪个显示屏上运行。该行为取决于清单文件以及 Intent 标记和选项(由启动 Activity 的实体设置)中定义的 Activity 启动模式。请参阅 ActivityOptions
,了解详细信息。
与折叠转换一样,当 Activity 移至辅助显示屏时,系统会更新上下文、调整窗口大小,并更改配置和资源。如果由该 Activity 来处理配置变更,则其会在 onConfigurationChanged()
中收到通知。如果不是,则其会重新启动。
如果配置变更已处理,则 Activity 应该在 onCreate
和 onConfigurationChanged
中检查当前显示屏。确保在显示屏变更时更新资源和布局。
如果为 Activity 选择的启动模式支持多个实例,则请记住,在辅助屏幕上启动时会新建一个 Activity 实例。这两个 Activity 会同时恢复。
一个 Activity 在多个显示屏中有多个实例。
您可能还需要阅读在 Android 8.0 中引入的现有多显示屏 API。
刘海屏
折叠和展开时,可折叠设备刘海屏的几何形状可能会有所不同。为避免出现刘海屏问题,请参阅刘海屏最佳实践。
Activity 上下文与应用上下文
在多显示屏模式下,使用适当的上下文至关重要。访问资源时,Activity 上下文(已显示)与应用上下文(未显示)不同。
Activity 上下文包含有关显示屏的信息,并且始终会针对它所在的显示屏区域进行调整。如要获取当前显示屏的指标和资源,请使用 Activity 上下文。此外,这还会影响某些使用上下文提供的信息的系统 API(例如 Toast)。
Activity 窗口配置和父级显示屏会定义资源和上下文。如要获取当前显示屏信息,请使用:
val activityDisplay = activity.windowManager.defaultDisplay
如要获取当前 Activity 窗口指标,请使用:
val windowMetrics = DisplayMetrics()
activityDisplay.getMetrics(windowMetrics)
或:
val windowMetrics = activity.resources.displayMetrics
使用辅助屏幕
您可以通过 DisplayManager
系统服务获取可用显示屏:
val dm = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val displays = dm.displays
使用 Display
类获取有关特定显示屏的信息:
如要确定 Activity 能否在某个显示屏上启动:
activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent)
如要在某个显示屏上启动 Activity:
val options = ActivityOptions.makeBasic()
options.launchDisplayId = targetDisplay.displayId
startActivity(intent, options.toBundle())
多显示屏支持
Android 现已支持软件键盘、壁纸和启动器。
软件键盘
如果显示屏已配置为支持系统装饰,则软件键盘可以在辅助屏幕上显示。如果某个文本字段请求在该显示屏上输入,输入法编辑器会自动显示。
辅助显示屏上的键盘。
壁纸
在 Android 10 (API 级别 29) 或更高版本 中,壁纸可以在辅助屏幕上显示。Android 框架会分别为每个显示屏创建单独的 WallpaperService.Engine
实例。请确保每个引擎的外观均为独立绘制。开发者可以使用 WallpaperService.Engine#getDisplayContext()
中的显示屏上下文加载资源。此外,请确保您的 WallpaperInfo.xml
文件设置 android:supportsMultipleDisplays="true"
。
手机和辅助显示屏上的壁纸。
启动器
有一个新的 intent 过滤器类别 SECONDARY_HOME
,可以为辅助屏幕提供专用 Activity。此 Activity 的实例可用在支持系统装饰的所有显示屏上,每个显示屏对应一个实例。
<activity>
...
<intent-filter>
<category android:name="android.intent.category.SECONDARY_HOME" />
...
</intent-filter>
</activity>
Activity 的启动模式必须符合以下条件:不会阻止多个实例,并且可以适应不同屏幕尺寸。启动模式不能是 singleInstance
或 singleTask
。
例如,Launcher3
的 AOSP 实现支持 SECONDARY_HOME
。
手机上的 Material Design 启动器。
辅助显示屏上的 Material Design 启动器。
测试
若要准备好应用,使其适合在可折叠设备上使用,您应该测试应用对以下各项的响应情况:
- 配置变更
- 多窗口和多项恢复
- 调整大小和新的屏幕宽高比
可折叠模拟器
AOSP 模拟器支持折叠设备。如此,开发者便可在折叠情形下测试其应用。
7.3 英寸可折叠模拟器
7.3 英寸 | 显示屏 | 分辨率 | 逻辑显示屏 | ||
尺寸 | X | Y | densityDpi | 尺寸 | |
展开时 | 7.3 | 1536 | 2152 | 420 | 大 |
折叠时 | 4.6 | 840 | 1960 | 420 | 正常 |
8 英寸可折叠模拟器
8 英寸 | 显示屏 | 分辨率 | 逻辑显示屏 | ||
尺寸 | X | Y | densityDpi | 尺寸 | |
展开时 | 8.03 | 2200 | 2480 | 420 | 大 |
折叠时 | 6.62 | 1148 | 2480 | 420 | 正常 |
AOSP 折叠模拟器。
测试多显示屏功能
利用强制桌面模式这一全新开发者选项,开发者可以在所有辅助显示屏上启用系统装饰支持,并在辅助显示屏(而不是默认显示屏)上显示鼠标指针。与启用自由窗口选项配合使用时,强制桌面会模拟多窗口桌面体验以及调整窗口大小的功能。
您可以使用模拟显示屏在 Pixel 上试用此功能。或者,如果您的设备支持 HDMI 或 DisplayPort over USB-C,您可以通过有线网络连接进行测试。
模拟显示屏。