前言
经过权限适配后,年后准备发版,无聊之中拿朋友的小米测试启动图适配,结果……
居然启动闪退……
报错信息:
java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
......
查了一下,这是源自Google AOSP代码里的bug,看来这又是适配到API26+的一个暗坑,简要记录一下此问题触发的缘由和环境
问题触发环境
某几个版本的Android8.0系统及其衍生ROM
触发条件
应用的targetSdkVerion=26+,Activity在Manifest中声明时,theme引用的style中包含了windowIsTranslucent="true"
,同时,activity标签本身的属性中包含了screenOrientation="portrait"
,即会在初始化此Activity时引发崩溃。
比如:
<!-- manifest里的activity声明 -->
<activity
android:name=".activity.SplashActivity"
android:screenOrientation="portrait"
android:theme="@style/SplashActivityTheme"/>
<!-- style.xml里面的样式声明 -->
<style name="SplashActivityTheme" parent="Theme.AppCompat.Light">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
这种样式声明常见于启动页,所以很容易复现。
产生原因
在某几个版本的Android O源码中,有如下逻辑,看起来Google希望通过这种方式告诉开发者不应该修改配置了translucent=true的activity的orientation,只不过这种方法有点过于2B……
//Code in Activity.java
//Need to pay attention mActivityInfo.isFixedOrientation() and ActivityInfo.isTranslucentOrFloating(ta)
if (getApplicationInfo().targetSdkVersion >= O_MR1 && mActivityInfo.isFixedOrientation()) {
final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
ta.recycle();
//Exception occurred
if (isTranslucentOrFloating) {
throw new IllegalStateException(
"Only fullscreen opaque activities can request orientation");
}
}
解决方法
目前Google在后续的版本中已经删除了这个2B的判断逻辑,但是部分基于问题源码的ROM仍然在市面上留存,防不胜防,因此此问题还是必须作出兼容适配。
问题的核心在于windowIsTranslucent="true"
和screenOrientation="portrait"
同时存在,所以处理方法是将Manifest声明中的screenOrientation
属性删掉,在Activity中根据版本手动指定Orientation。
以上面的SplashActivity声明为例
<!-- manifest里的activity声明 -->
<activity
android:name=".activity.SplashActivity"
android:theme="@style/SplashActivityTheme"/>
Activity的Java代码
// 在onCreate中手动指定orientation
@Override
public void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
init();
}
相关讨论
java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation