如何在 AndroidManifest.xml 中禁止 Activity 随屏幕旋转?

解读

国内面试官问“禁止旋转”时,往往不只是想听一句“写死 portrait”。他真正想确认的是:

  1. 你是否清楚 Activity 生命周期会因配置变更而重启;
  2. 你是否知道 manifest 层面与代码层面两种做法的区别;
  3. 你是否理解国产 ROM(如 MIUI、EMUI、ColorOS)对加速度传感器旋转策略的二次定制,以及折叠屏、平板、外接副屏等场景下的兼容性隐患;
  4. 你是否能权衡“禁止旋转”对用户体验、多窗口、分屏、投屏、车载横屏模式的副作用。

因此,回答时要先给出最简洁可靠的 manifest 写法,再主动补充“为什么”和“还有什么坑”。

知识点

  • configChanges 与 orientation、screenSize、screenLayout 的关系
  • android:screenOrientation 的枚举值:portrait、sensorPortrait、locked、userPortrait、nosensor 等
  • 国产机“自动旋转”开关与系统 Settings.System.ACCELEROMETER_ROTATION 的联动逻辑
  • 折叠屏展开/收起会触发 screenSize + smallestScreenSize,若只拦截 orientation 仍会重启 Activity
  • Android 12L 以上大屏设备强制要求支持横屏,Google Play 政策已警告“锁定方向导致体验不佳”的应用
  • 车载、TV、投屏场景下,系统会忽略 portrait 锁定,直接以横屏启动,若布局未做横屏适配会直接变形
  • 国内渠道包常见需求:manifest 里统一锁定,但某些渠道(如华为折叠屏专区)要求可横屏,需 build.gradle 中利用 manifestPlaceholders 动态替换
  • 安全与性能:锁定方向可减少一次 Activity 重启,降低 onSaveInstanceState/onRestoreInstanceState 的耗时,但长期持有固定方向可能使加速度传感器持续工作,增加 1~2 mA 电流(实验室数据)

答案

在 AndroidManifest.xml 中对目标 Activity 节点增加以下两个属性即可彻底禁止因旋转导致的重启与方向变化:

<activity android:name=".ui.MainActivity" android:screenOrientation="portrait" android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize" ... />

解释:

  1. android:screenOrientation="portrait" 把方向写死为竖屏,系统不再根据传感器切换。
  2. configChanges 里把 orientation、screenSize、screenLayout、smallestScreenSize 全部声明,确保折叠屏、外接副屏、分屏拖动等场景下 Activity 不会被重建。
  3. 如果项目最低目标 SDK ≥ 31,建议把 screenOrientation 改为 "userPortrait",允许用户在系统设置里手动开启“强制横屏”时仍可切换,避免被 Google Play 大屏政策警告。
  4. 国产渠道差异化:在 build.gradle 中定义 manifestPlaceholders,CI 打包时根据渠道决定是否注入 portrait 或 sensor,模板如下:
    manifestPlaceholders = [ORIENTATION: "portrait"]
    manifest 中写成 android:screenOrientation="${ORIENTATION}",即可一条代码打出可旋转与不可旋转双包。

拓展思考

  1. 只在 manifest 锁定方向并不能阻止“系统设置-显示-强制横屏”或开发者选项“强制所有应用可调整方向”的第三方工具,此时仍需在代码里加 OrientationEventListener 做二次校正,但会引入电量与线程开销,面试时可作为“兜底方案”提及。
  2. 对于视频播放、相机预览、游戏等场景,更推荐“动态锁定”:进入页面时读取当前方向,立即 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED),退出时恢复,兼顾沉浸体验与系统策略。
  3. 折叠屏展开后,系统会把应用迁移到更大的 Display,若你在 manifest 里声明了最大宽高比 android:MaxAspectRatio 或 resizeableActivity=false,可能导致应用被强制重启甚至黑边,锁定方向时务必同步测试展开/收起动画与多窗口模式。
  4. 车载项目(Android Automotive)中,系统完全忽略 portrait,所有页面必须以横屏布局设计,此时禁止旋转已无意义,应把重点放在 dp 宽度适配与方向盘焦点导航上。
  5. 面试反问环节可以主动问:“咱们业务场景里是否有投屏、折叠屏、车载或 Pad 版本?如果后续需要横屏,我这套 manifest 占位符方案能否直接复用?”——既展示前瞻性,也体现对国内多设备生态的敏感度。