Android 8.0 只有全屏不透明活动可以请求方向问题
1 背景
Android 8.0
,即sdk
为26
时,Android
为了支持全面屏系统增加了一个限制,如果是透明的Activity
,则不能固定它的方向,因为它的方向其实是依赖其父Activity
的(因为透明);- 因此产生了一个系统级别的
Bug
,当以下四个条件同时满足时会发生的崩溃: - 1)使用的是
Android 8.0
操作系统的设备; - 2)
targetSdkVersion
设置为27
以上; - 3)将背景设置为透明主题;
- 4)固定屏幕方向,
screenOrientation
的值为portrait
或者landscape
(代码或者清单文件); - 崩溃信息如下所示:
1 | java复制代码Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation |
2 分析
- 通过
Only fullscreen opaque activities can request orientation
报错信息可知,这是Android 8.0 Activit
的源码所抛出的异常错误信息,源码如下所示:
1 | java复制代码public class Activity { |
- 通过阅读上述的源码可知,触发
IllegalStateException
异常的条件有: - 1)
Activity
屏幕方向固定,windowIsTranslucent = true
; - 2)
Activity
屏幕方向固定,windowIsTranslucent = false
,windowSwipeToDismiss = true
; - 3)
Activity
屏幕方向固定,windowIsFloating = true
。
3 解决思路
- 1)[不推荐] 暴力回退
sdk
版本,即sdk <= 26
; - 2)[不推荐] 去除主题中的透明属性,需求允许的话:
1 | xml复制代码<item name="android:windowIsTranslucent">false</item> |
- 3)[不推荐] 指定除
8.0
以外的系统固定屏幕方向,去掉清单文件中screenOrientation
属性,activity
中onCreate
中执行屏幕方向固定的代码:
1 | java复制代码if (android.os.Build.VERSION.SDK_INT != android.os.Build.VERSION_CODES.O) { |
- 4)[不推荐] 如果你前一个页面和需要透明主题的界面屏幕方向一致,我们只需要在清单文件中配置
android:screenOrientation="behind"
,behind
的意思就是和之前页面的屏幕方向保持一致; - 5)[推荐] 通过反射,让系统绕过屏幕方向的检测,设置屏幕不固定:
1 | kotlin复制代码open class FixOreoOrientationActivity: AppCompatActivity() { |
- 注意:
- 上述的
FixOreoOrientationActivity
代码为反编译懂车帝Android
代码中获取,由此可见在应用市场已得到有效验证; - 其次因为上代码涉及到反射,这些
API
在未来的Android
版本中可能会改变或不再可访问,这可能导致你的应用在未来的Android
版本上出现问题,所以需要关注Android
版本升级相关变更信息,从而持续维护该方法。
本文转载自: 掘金