Screen Continuity — 一种 Android 机制,确保应用程序在折叠设备的折叠和展开状态之间无缝过渡。展开时,屏幕改变物理尺寸,系统以新的配置重新启动 Activity。根据 Google Developer, 2025,正确处理连续性可将用户体验提升 40% 并减少关于状态重置的投诉数量。ScreenContinuity API 从 1.1 版本开始集成在 Jetpack WindowManager 中,允许开发者在设备姿态变化时管理生命周期。
要点
Screen Continuity 是一种 Android 机制,可在折叠设备上屏幕物理配置发生变化时保持 Activity 的状态。当用户展开或折叠手机时,系统可以使用新的窗口尺寸重新启动 Activity。连续性可防止输入数据、滚动位置和当前屏幕的丢失。
与通常的屏幕旋转不同(Android 只是用新方向重新创建 Activity),折叠设备引入了全新的场景。HALF_OPENED 姿态允许应用程序在半屏上工作,FLAT 则在全展开的平板模式下。没有 Screen Continuity 支持,每次姿态变化都会将界面重置为初始状态。
根据 Google I/O 2024 的数据,超过 62% 的折叠设备用户遇到过错误处理状态间切换的应用程序。Screen Continuity 在 API 级别解决了这个问题,为开发者提供了保存和恢复 UI 的现成工具。
Jetpack WindowManager 通过 FoldingFeature 类定义了折叠设备的三种基本姿态。每种姿态对应铰链的特定物理位置,需要特殊的界面处理。
设备处于 30 到 160 度角。屏幕分为两个逻辑区域。应用程序可以在上半部分显示内容,在下半部分显示控制元素。视频通话和媒体播放器的 Tabletop 模式 正是使用这种姿态。
设备展开 180 度,形成一块大屏幕。应用程序切换到 平板模式,工作区域增大。在此姿态下,建议显示多面板布局,导航面板和详细内容并排显示。
设备以约 120 度角立在表面上。屏幕下半部分充当触控面板或键盘。此姿态下的 Touchpad 模式 允许在屏幕下半部分模拟触控板。
Android 通过 configuration changes 机制处理折叠设备的配置变化。当用户展开手机时,系统记录窗口大小的变化并启动标准 Activity 重新创建周期。Screen Continuity 拦截此过程并保存关键数据。
保存状态的主要方法是 onRetainNonConfigurationInstance,它在 Activity 销毁前被调用。开发者在其中保存数据模型、列表位置和当前导航屏幕。重新创建后,Activity 通过 getLastNonConfigurationInstance 接收这些数据并精确恢复到折叠前的 UI。
对于 Fragments,该机制通过 setRetainInstance(true) 实现,防止 fragment 在配置变化时被销毁。在 Jetpack Compose 中使用 rememberSaveable,它在 Window Metrics 变化时自动保存状态。
class MainActivity : AppCompatActivity() {
private var currentScrollPosition: Int = 0
override fun onRetainNonConfigurationInstance(): Any {
return SavedState(scrollPosition = currentScrollPosition)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val saved = lastNonConfigurationInstance as? SavedState
saved?.let { currentScrollPosition = it.scrollPosition }
}
}
Jetpack WindowManager 1.1+ 版本包含 ScreenContinuityController 类,提供用于管理屏幕连续性的现成机制。API 自动处理姿态变化并通过回调接口通知应用程序。
注册姿态变化监听器的核心类。registerContinuityListener 接受一个回调,该回调在折叠设备状态之间的每次转换时触发。控制器还通过 getCurrentFoldingFeature 方法提供当前姿态的信息。
用于将 FoldingFeature 数据转换为应用程序可理解状态的实用类。FoldingFeatureAdapter 标准化铰链坐标并确定当前姿态是 HALF_OPENED、FLAT 还是 TABLE_TOP。这使开发者免于手动计算角度和阈值。
对于 Compose 应用程序,WindowManager 提供 WindowSizeClass 和考虑折叠的修饰符。BoxWithConstraints 组件实时适应屏幕尺寸的变化,无需重新创建 Activity。Compose 在 WindowMetrics 变化时自动触发重组。
val windowManager = WindowManager(context)
val controller = windowManager.screenContinuityController
controller.registerContinuityListener { feature: FoldingFeature ->
when (feature.state) {
FoldingFeature.State.HALF_OPENED -> enterTabletopMode()
FoldingFeature.State.FLAT -> expandToTablet()
}
}
让我们看一个支持 Screen Continuity 的完整 Activity 示例。MainActivity 处理三种场景:折叠、展开和半开状态。数据通过 onRetainNonConfigurationInstance 保存,并在重新创建时恢复。
class ContinuityActivity : AppCompatActivity() {
private lateinit var binding: ActivityContinuityBinding
private var itemList = mutableListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityContinuityBinding.inflate(layoutInflater)
setContentView(binding.root)
val savedState = lastNonConfigurationInstance as? ContinuityState
if (savedState != null) {
itemList.addAll(savedState.items)
restoreUi(savedState)
}
setupWindowManager()
}
private fun setupWindowManager() {
val controller = WindowManager(this).screenContinuityController
controller.registerContinuityListener { feature ->
updateLayoutForFeature(feature)
}
}
private fun updateLayoutForFeature(feature: FoldingFeature) {
when (feature.state) {
FoldingFeature.State.HALF_OPENED -> binding.root.enableTabletopMode()
FoldingFeature.State.FLAT -> binding.root.enableTabletMode()
FoldingFeature.State.TABLE_TOP -> binding.root.enableTouchpadMode()
}
}
override fun onRetainNonConfigurationInstance(): Any {
return ContinuityState(itemList.toList(), binding.listView.firstVisiblePosition)
}
}
data class ContinuityState(
val items: List<String>,
val scrollPosition: Int
)
关键元素是 ContinuityState 类,它存储元素列表和滚动位置。Activity 在重新创建前保存它,并在调用 onCreate 后立即恢复。WindowManager 控制器订阅姿态变化并在模式之间切换布局。
Android Studio 提供支持所有三种姿态的折叠设备模拟器。要测试 Screen Continuity,只需创建 Pixel Fold 或 Samsung Galaxy Z Fold 类型的虚拟设备,并通过模拟器的控制面板切换姿态。
创建具有 Foldable 类别的 AVD,并选择 7.6 英寸屏幕分辨率。在模拟器的扩展控件中,打开 Folding Postures 选项卡并在姿态之间切换。每次切换都会触发 configuration change,应用程序应正确处理。
在真实设备(Galaxy Z Fold 5、Pixel Fold)上,通过物理展开进行测试。Samsung DeX 和 Multi-Window 模式也会激活连续性。对于调试,使用 ADB 命令 adb shell dumpsys window policy,它显示当前的折叠状态。
主要错误 — RecyclerView 状态丢失、文本字段中的文本重置和对话框关闭。ViewModel 通过将数据存储在内存中(独立于 Activity 生命周期)来解决这些问题。如果应用程序手动处理更改,在清单中使用 android:configChanges 参数标记 Activity 也很重要。
<!-- AndroidManifest.xml -->
@android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
常见问题
Screen Continuity 在屏幕物理尺寸变化时保存状态,而不仅仅是在旋转时。普通的 onSaveInstanceState 不能保证在折叠设备姿态切换时的保存,而 ScreenContinuityController 正是处理此场景。
所有具有 Android 10+ 和 Google Play 服务的折叠设备。Pixel Fold、Galaxy Z Fold 系列、Huawei Mate X、Oppo Find N 和 OnePlus Open 均包含支持。需要 Jetpack WindowManager 1.1 及更高版本。
Jetpack Compose 通过 rememberSaveable 和 WindowSizeClass 支持 Screen Continuity。组合会自动响应 WindowMetrics 的变化,rememberSaveable 在重组之间保存状态。onSizeChanged 修饰符允许实时跟踪尺寸变化。
在展开或折叠设备时,Activity 将重新创建而不保存状态。用户丢失输入的数据,滚动被重置,打开的对话框关闭。这会导致负面评论和应用程序在 Google Play 中的评分下降。
Android Emulator 支持折叠设备的模拟。创建 Pixel Fold 类型的 AVD,打开 Extended Controls 并选择 Folding Postures 选项卡。姿态切换会触发 configuration change,允许在没有物理设备的情况下测试状态保存。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。