背景
对于面向谷歌开发的牛马来讲,必须时刻关注谷歌的新特性以及新政策,因为如果不这么做的话,你的应用迟早会在play商店里面遭到下架的警告,这不现在已经6月了,还有两个半月就要到八月31号了,虽然官方目前还没有明确说明,但是按照过去两年的时间线,有一件事情不得不马上要提到todo List里面去了,那就是targetSdkVersion需要升级到36

而今天这篇文章要讨论的是如何去适配Android16里面的其中一个特性--自适应布局,官方文档上有一段说明,大概的意思是Android 平台正朝着应用需要适应各种屏幕方向、显示屏尺寸和宽高比的模式发展,固定屏幕方向或限制尺寸调整会阻碍应用在大屏设备上的适应性,对于以 Android 16(API 级别 36)为目标平台的应用,屏幕方向、尺寸可调整性和宽高比限制不再适用于最小宽度 >= 600dp 的显示屏,无论宽高比或用户偏好的屏幕方向如何,应用都会填满整个显示窗口,且不会采用竖条模式。
值得注意的是,Android16提供了一个开关,关闭后你的应用将不会受到这个特性的影响,以前怎么样现在还是怎么样,但是到了Android17,这个开关也将被废弃,也就是Android17就要强制打开这个特性了,根据以往的经验就能知道,凡事带开关的特性,适配起来的工作量都不会小,比如edge-to-edge,16kb或者预测性返回,所以我们也应当好好规划下这个自适应布局应该如何去适配
即将被忽略的属性与API
其实如何你的应用有发布至谷歌市场,一定会在后台看见过谷歌早在几个月前就有给你的app发过一个用户体验类型的整改建议,内容就是将项目中的尺寸调整以及屏幕方向的限制去除掉

那么具体是哪些限制呢,官方也列出来了
AndroidManifest 属性
| 属性 | 说明 |
|---|---|
android:screenOrientation |
所有锁定值均被忽略(portrait、landscape、sensorPortrait 等) |
android:resizableActivity |
false 设置不再生效 |
android:minAspectRatio |
无效果 |
android:maxAspectRatio |
无效果 |
运行时 API
| API | 说明 |
|---|---|
setRequestedOrientation() |
被忽略 |
getRequestedOrientation() |
返回值不再代表实际行为 |
被忽略的 screenOrientation 取值
portrait, reversePortrait, sensorPortrait, userPortrait,
landscape, reverseLandscape, sensorLandscape, userLandscape
例外情况
以下三种情况下,方向/尺寸限制不会被忽略:
| 例外 | 条件 | 说明 |
|---|---|---|
| 游戏 | android:appCategory 标记为 game |
游戏类应用豁免 |
| 用户明确选择 | 用户在设备宽高比设置中主动启用 | 用户自主决定 |
| 小屏设备 | 屏幕最小宽度 < 600dp(sw600dp) | 手机等小屏设备不受影响 |
适配方案
方案一:临时豁免,仅适用于Android16
这个就是上面提到过的开关,到了Android17后,这个开关将会无效,具体怎么设置呢?看代码 在 <activity> 或 <application> 级别添加属性,暂时恢复旧行为:

这种方式只能作为过渡方案,并不能作为最终方案,只有当你的项目适配工作量太大,或者存在部分三方sdk无法短期适配的时候,才可以使用,给自己留出一些适配时间
方案二:自适应布局改造(Compose)
引入 WindowSizeClass


Compose Material 3 自适应布局组件
| 组件 | 用途 | 行为 |
|---|---|---|
NavigationSuiteScaffold |
自适应导航 | 紧凑→底部导航栏,展开→侧边导航栏 |
ListDetailPaneScaffold |
列表-详情 | 紧凑→单窗格,展开→双窗格并排 |
SupportingPaneScaffold |
辅助窗格 | 主窗格+辅助窗格自适应 |

方案三:自适应布局改造(View)
Compose的方案是挺方便,但是绝大多数项目应该还停留在传统View的层面上,对于这类项目,应该如何适配?
使用 SlidingPaneLayout

利用 ConstraintLayout 百分比布局

动态判断布局

Configuration 自适应 + 备用布局资源
使用 Android 资源限定符提供多套布局:

方案四:相机预览专项适配
1.使用 CameraX 的 PreviewView

2.使用 Camera2 时手动处理方向

参考文档: 管理相机预览
方案五: Activity 重建与状态保存
现在既然不固定方向了,那么设备自然会经常会旋转,旋转后的Activity会重建,里面的状态必须好好保存一下
ViewModel + SavedStateHandle

onSaveInstanceState

验证方案
启用兼容性标志快速测试
在开发阶段,通过adb强制启用行为,可以提前发现问题:

使用 DeviceConfigurationOverride 测试
Compose 1.7+ 支持在单台设备本地模拟不同配置:

可调整大小模拟器
Android Studio提供可调整大小模拟器,可以切换不同分辨率大小的屏幕,模拟不同的设备

方式就是在模拟器的设备里面,选择Displays,添加不同的display配置就好了

最后来点吐槽
文章写到这,整个适配过程差不多也结束了,谷歌真是一天天不给人活路,这种适配对于老项目,尤其是内部穿插着各种二方库,三方库的app来讲,简直是个灾难。。。可以说比16kb还恶心,16kb不管咋样,不会让你去改业务代码,顶多哪个库升级了改些废弃的api就好了,但是这个适配,没那么简单,业务代码多多少少需要动到一些,对于维护过老项目,那种屎山项目的人都清楚,业务代码随便改一行动一行,带来的后果可能都是很可怕的,坑估计是少不了的了。。。