如何检测设备是否为折叠屏?
解读
在国内面试中,这道题考察的是“对非常规屏幕形态的系统级适配能力”。折叠屏手机(华为 Mate X 系列、荣耀 Magic V、OPPO Find N、vivo X Fold 等)已经批量上市,厂商对“大屏利用率”和“连续交互体验”有 KPI 要求,因此面试官希望候选人:
- 能第一时间给出“官方推荐 API”,避免用反射或民间字段;
- 知道在哪些生命周期回调里判断,防止因窗口大小变化而重复弹窗或重建任务;
- 了解国内 ROM 差异化(例如华为 EMUI 的超大屏模式、小米 MIUI 的平行窗口)对判断结果的影响;
- 能把“折叠屏检测”与“窗口大小类、Configuration、Jetpack WindowManager”串成体系,体现架构思维。
知识点
- Jetpack WindowManager 1.0+(androidx.window:window)——Google 官方折叠屏适配库,提供 WindowInfoRepository、 FoldingFeature、DeviceState。
- FoldingFeature 的 isSeparating、orientation、state(FLAT / HALF_OPENED)、occlusionType(FULL / NONE)。
- Configuration.uiMode、screenLayout、smallestScreenWidthDp 的“传统字段”局限:只能拿到“屏幕大或小”,无法区分“折叠/展开/半折”。
- Activity 生命周期与 WindowMetricsCalculator:在 onStart() 之后监听、在 onStop() 之前移除,防止泄漏。
- 国内 ROM 的“平行视窗”“超大屏强制缩放”开关:可能让 smallestScreenWidthDp 失真,需要结合 FoldingFeature 二次校验。
- 权限:Jetpack WindowManager 不需要额外权限,但后台监听窗口变化会被系统节流,需绑定前台生命周期。
- Kotlin Flow/Channel 与 LiveData 的桥接:实现“窗口状态驱动 UI”的 MVVM 案例。
答案
给出可直接写进简历项目的“官方方案”代码骨架,并口头补充面试话术:
// 1. 依赖
implementation("androidx.window:window:1.2.0")
// 2. 在 Activity/Fragment 中
class MainActivity : AppCompatActivity() {
private lateinit var windowInfoRepo: WindowInfoRepository
private val scope = lifecycleScope + Dispatchers.Main.immediate
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
windowInfoRepo = WindowInfoRepository.create(this)
// 3. 注册折叠状态回调
scope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
windowInfoRepo.windowLayoutInfo
.collect { layoutInfo ->
val foldingFeature = layoutInfo.displayFeatures
.filterIsInstance<FoldingFeature>()
.firstOrNull()
val isFolded = when {
foldingFeature == null -> false // 非折叠屏
foldingFeature.state == FoldingFeature.State.FLAT -> false
foldingFeature.isSeparating -> true // 半折或全折
else -> false
}
// 4. 通知 UI 层刷新
viewModel.onFoldStateChanged(isFolded)
}
}
}
}
}
面试话术: “国内项目里我会优先使用 Jetpack WindowManager,它在华为、荣耀、OPPO、vivo 等折叠屏机型上已内置适配,无需反射。通过 FoldingFeature.isSeparating 可以准确知道屏幕是否被铰链分隔,再叠加 smallestScreenWidthDp 判断展开后的真实宽度,就能完成‘折叠/展开/半折’三态适配。整个监听绑定在 lifecycleScope,防止泄漏,也符合 MVVM 单向数据流。”
拓展思考
- 多窗口/分屏场景:FoldingFeature 的 occlusionType 会返回 FULL,表示铰链遮挡区域,此时可自动把 RecyclerView 的 item 间距增大,避免内容被“折痕”截断。
- 桌面模式(Samsung DeX、华为电脑模式):虽然屏幕物理尺寸变大,但 FoldingFeature 为 null,需要额外检测 Configuration.uiMode 是否包含 UI_MODE_TYPE_DESK,防止误判成“展开”。
- 自动化测试:使用 androidx.test.uiautomator + WindowManagerShellHelper 模拟 HALF_OPENED 状态,验证折叠动画期间是否发生重启或闪屏。
- 性能:折叠瞬间会触发 Configuration change,如果 Activity 未声明 android:configChanges="screenSize|smallestScreenSize|screenLayout",会默认重建;在大项目里建议把 configChanges 交给 ViewModel + SavedStateHandle 处理,避免瞬间双重初始化。
- 隐私合规:国内应用常把“设备形态”埋点到大数据平台,需脱敏(只传 0/1/2 枚举),避免明文上传 FoldingFeature 原始对象,防止被认定为“读取硬件敏感信息”。