前言
不得不说 Google 的适配是真的烦。真的是一不小心各种坑,市面上的 Android 版本也很多,各种各样的屏幕也很多。最近做的项目在自己手上测试的都还行,直接丢给客户测试的时候,客户手机是 Android 8.0 的,直接崩溃了。异常如下
1
|
Only fullscreen activities can request orientation
|
在源码中看看是为什么报的异常吧
1
2
3
4
5
6
7
8
9
10
|
if (getApplicationInfo().targetSdkVersion > O && mActivityInfo.isFixedOrientation()) {
final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
ta.recycle();
if (isTranslucentOrFloating) {
throw new IllegalStateException(
"Only fullscreen opaque activities can request orientation");
}
}
|
从上述可以看到条件,大于了 Android O 也就是 target 26 , 加上如果是固定了屏幕就会报出异常
一共有3个条件
- targetSdkVersion
- isFixedOrientation ()
- ActivityInfo.isTranslucentOrFloating(ta)
再看看决定的条件是什么
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public static boolean isTranslucentOrFloating(TypedArray attributes) {
final boolean isTranslucent =
attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
false);
final boolean isSwipeToDismiss = !attributes.hasValue(
com.android.internal.R.styleable.Window_windowIsTranslucent)
&& attributes.getBoolean(
com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
final boolean isFloating =
attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating,
false);
return isFloating || isTranslucent || isSwipeToDismiss;
}
|
是否设置了 Activity 透明
1
2
3
4
|
public boolean isFixedOrientation() {
return isFixedOrientationLandscape() || isFixedOrientationPortrait()
|| screenOrientation == SCREEN_ORIENTATION_LOCKED;
}
|
是否是设置了横屏和竖屏或者锁定了 screenOrientation == SCREEN_ORIENTATION_LOCKED
好了,结论已经出来了,target 这个先放弃了,因为现在大部分的开发者都适配高版本了。然后要么就是不设置 Activity 透明。要么就是不设置屏幕方法,或者让 screenOrientation 不等于 SCREEN_ORIENTATION_LOCKED
关于这个异常 Google 已经在 8.1 中解决了,但是市面上还是有很多 8.0 的手机的,也还是要解决。而我的项目中透明这个是要的。也就只能修改 screenOrientation == SCREEN_ORIENTATION_LOCKED 这个条件了
解决方案
修改 screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED 由于我项目采用的是组件化 theme 过多,错综复杂,不太好手动在清单文件中修改,所以我采用了反射的方式,根据版本去反射对应的 API
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
public class ActivityHook {
/**
* java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
* <p>
* 修复android 8.0存在的问题
* <p>
* 在Activity中onCreate()中super之前调用
*
* @param activity
*/
public static void hookOrientation(Activity activity) {
//目标版本8.0及其以上
if (activity.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.O) {
if (isTranslucentOrFloating(activity)) {
fixOrientation(activity);
}
}
}
/**
* 设置屏幕不固定,绕过检查
*
* @param activity
*/
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();
}
}
/**
* 检查屏幕 横竖屏或者锁定就是固定
*
* @param activity
* @return
*/
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;
}
}
|
### 在需要的Activity中使用
1
2
3
4
5
6
7
8
|
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
ActivityHook.hookOrientation(this);//hook,绕过检查
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xxxx);
}
|
参考博客:
https://www.jianshu.com/p/8328a586f9de
https://blog.csdn.net/starry_eve/article/details/82777160