前言
這幾天在Sentry上發(fā)現(xiàn)了1個(gè)從未見過的異常
java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
印象中從未遇到過這個(gè)問題烘挫,但也一時(shí)覺得莫名其妙,經(jīng)過查證是只有Android8.X版本才會(huì)出現(xiàn)的bug,而且估計(jì)很少有人遇到饮六,既然自己解決了也就把怎么解決的說一下其垄。
產(chǎn)生原因
簡單來說滿足3個(gè)條件時(shí)會(huì)報(bào)這個(gè)異常
1)當(dāng)前Activity是否固定了方向,例如android:screenOrientation="portrait"
2)當(dāng)前Activity的主題是否設(shè)置了如下的屬性:
windowIsTranslucent為true
windowIsTranslucent為false卤橄,但windowSwipeToDismiss為true
windowIsFloating為true
3)項(xiàng)目的targetSdkVersion是否為26或27即Android8.X版本
當(dāng)滿足以上條件你又去打開那個(gè)Activity绿满,這個(gè)bug就會(huì)如約而至
解決方案
這里就直接上代碼吧
/**
* 修復(fù)Android8.X存在的java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation問題
* 在Activity中onCreate()中super之前調(diào)用
*
* @author yzt 2020/6/30
*/
public class ActivityOrientationHook {
public static void hook(Activity activity) {
if (activity == null)
return;
//目標(biāo)版本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;
//調(diào)用檢查是否屏幕旋轉(zhuǎn)
Method isTranslucentOrFloatingMethod = ActivityInfoClass.getDeclaredMethod("isTranslucentOrFloating", TypedArray.class);
isTranslucentOrFloatingMethod.setAccessible(true);
isTranslucentOrFloating = (boolean) isTranslucentOrFloatingMethod.invoke(null, typedArray);
} catch (Exception e) {
e.printStackTrace();
}
return isTranslucentOrFloating;
}
/**
* 設(shè)置屏幕不固定窟扑,繞過檢查
*/
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);
//設(shè)置屏幕不固定
activityInfo.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后在對(duì)應(yīng)的Activity中這么使用即可
@Override
protected void onCreate(Bundle savedInstanceState) {
ActivityOrientationHook.hook(this);
super.onCreate(savedInstanceState);
}
解決思路就是判斷targetSdkVersion版本喇颁,如果為8.X版本則不固定方向,來達(dá)到規(guī)避這個(gè)異常的目的嚎货。由于這個(gè)問題在9.0及以上的版本已經(jīng)解決橘霎,所以這里只要判斷一下是否是8.X版本即可。
在此感謝
https://blog.csdn.net/na2609613672/article/details/89403053
http://www.reibang.com/p/8328a586f9de