前言
这几天在Sentry上发现了1个从未见过的异常
java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
印象中从未遇到过这个问题,但也一时觉得莫名其妙,经过查证是只有Android8.X版本才会出现的bug,而且估计很少有人遇到,既然自己解决了也就把怎么解决的说一下。
bug.png
产生原因
简单来说满足3个条件时会报这个异常
1)当前Activity是否固定了方向,例如android:screenOrientation="portrait"
2)当前Activity的主题是否设置了如下的属性:
windowIsTranslucent为true
windowIsTranslucent为false,但windowSwipeToDismiss为true
windowIsFloating为true
3)项目的targetSdkVersion是否为26或27即Android8.X版本
当满足以上条件你又去打开那个Activity,这个bug就会如约而至
解决方案
这里就直接上代码吧
/**
* 修复Android8.X存在的java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation问题
* 在Activity中onCreate()中super之前调用
*
* @author yzt 2020/6/30
*/
public class ActivityOrientationHook {
public static void hook(Activity activity) {
if (activity == null)
return;
//目标版本8.X
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
if (isTranslucentOrFloating(activity)) {
fixOrientation(activity);
}
}
}
/**
* 检查屏幕是否固定,横竖屏或者锁定就是固定的
*/
private static boolean isTranslucentOrFloating(Activity activity) {
boolean isTranslucentOrFloating = false;
try {
Class<?> styleableClass = Class.forName("com.android.internal.R$styleable");
Field WindowField = styleableClass.getDeclaredField("Window");
WindowField.setAccessible(true);
int[] styleableRes = (int[]) WindowField.get(null);
//先获取到TypedArray
final TypedArray typedArray = activity.obtainStyledAttributes(styleableRes);
Class<?> ActivityInfoClass = ActivityInfo.class;
//调用检查是否屏幕旋转
Method isTranslucentOrFloatingMethod = ActivityInfoClass.getDeclaredMethod("isTranslucentOrFloating", TypedArray.class);
isTranslucentOrFloatingMethod.setAccessible(true);
isTranslucentOrFloating = (boolean) isTranslucentOrFloatingMethod.invoke(null, typedArray);
} catch (Exception e) {
e.printStackTrace();
}
return isTranslucentOrFloating;
}
/**
* 设置屏幕不固定,绕过检查
*/
private static void fixOrientation(Activity activity) {
try {
Class<Activity> activityClass = Activity.class;
Field mActivityInfoField = activityClass.getDeclaredField("mActivityInfo");
mActivityInfoField.setAccessible(true);
ActivityInfo activityInfo = (ActivityInfo) mActivityInfoField.get(activity);
//设置屏幕不固定
activityInfo.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后在对应的Activity中这么使用即可
@Override
protected void onCreate(Bundle savedInstanceState) {
ActivityOrientationHook.hook(this);
super.onCreate(savedInstanceState);
}
解决思路就是判断targetSdkVersion版本,如果为8.X版本则不固定方向,来达到规避这个异常的目的。由于这个问题在9.0及以上的版本已经解决,所以这里只要判断一下是否是8.X版本即可。
在此感谢
https://blog.csdn.net/na2609613672/article/details/89403053
//www.greatytc.com/p/8328a586f9de