Android 8.0透明Activity报错 "Only fullscreen activities can request orientation"
1、分析问题
首先,我的代码是这样的:
style.xml
true
true
adjustPanfalse
@color/app_transparent_color
true//透明true//悬浮
AndroidManifest.xml
从上面可以看出,我的activity是一个状态栏透明并且背景透明的activity。在26的编译版本时是可以正常的使用的,但是当把编译版本升级到27时,就会出现”Only fullscreen activities can request orientation”异常。这是google出于安全的考虑,对android8.0以后的版本做的处理,当一个Activity固定方向并且是透明的,在8.0以后的版本中就会抛出异常。相关源码如下:
Entry ent = AttributeCache.instance().get(packageName,realTheme, com.android.internal.R.styleable.Window, userId);
final boolean translucent = ent != null && (ent.array.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent, false)|| (!ent.array.hasValue(
com.android.internal.R.styleable.Window_windowIsTranslucent) && ent.array.getBoolean(com.android.internal.R.styleable.Window_windowSwipeToDismiss,false)));
fullscreen = ent != null && !ent.array.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array);
noDisplay = ent != null && ent.array.getBoolean(com.android.internal.R.styleable.Window_windowNoDisplay, false);
if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen && appInfo.targetSdkVersion >= O) {
throw new IllegalStateException("Only fullscreen activities can request orientation");
}
上面是27的源码片段,通过上面我们可以看出当三个条件同时满足的时候,系统会抛出”Only fullscreen activities can request orientation”异常。先分别来说说这三个条件都表示什么意思:
ActivityInfo.isFixedOrientation(requestedOrientation) —— 表示判断当前的|Activity是否固定了方向
fullscreen —— 表示Activity是否是透明的或者是否悬浮在Activity上,是透明的或者悬浮在Activity上fullscreen就等于false
appInfo.targetSdkVersion >= O —— 表示版本号大于等于26
当以上的三个条件同时满足的时候,系统框架就会抛出异常。
2、解决问题的方法
这个问题在最新的SDK中已经修复,我们在API Level 27的设备上已经无法重现,但我们手头的API Level 26的设备还是能重现。而且根据上面的代码来看,如果想保留当前Activity的style,“isTranslucentOrFloating”的逻辑根本没法绕过,所以想绕开很难,目前能想到的大概两个方向:
1.推迟SDK升级,等官方修复被大多数设备采用;
2.升级SDK,但重构一下代码,看看已有的非“fullscreen” Activity是不是都是必要的,例如用Fragment实现周围半透明效果,能不能直接把Fragment加入到当前Activity(当然Detach Fragment是有重绘View的开销的)。
3.使用Dialog代替透明的Activity
4.不固定Activity的方向
5.使用不透明且不是悬浮的主题(我采用此解决办法,8.0以后改为不透明不悬浮)