Only fullscreen opaque activitie
出现Only fullscreen opaque activities can request orientation是谷歌爸爸在安卓8.0版本时为了支持全面屏,增加了一个限制:如果是透明的Activity,则不能固定它的方向,因为它的方向其实是依赖其父Activity的(因为透明)。然而这个bug只有在8.0中有,8.1中已经修复。还有种原因是代码中手动取消App启动白屏或者黑屏的时候,将Splash界面设为了透明,然后这个时候又设置了方向为垂直,从而导致了这个问题。总结具体原因有两种:
1.Activity的风格为透明,在manifest文件中指定了一个方向,则在onCreate中崩溃
2.Activity的风格为透明,如果调用setRequestedOrientation方法固定方向,就会崩溃
解决方法
方法一:
1.找到你设置透明的Activity,然后在他的theme中将android:windowIsTranslucent改为false
即:<item name="android:windowIsTranslucent">false</item>
2.再加入<item name="android:windowDisablePreview">true</item>就搞定了。
方法二:
如果项目结构复杂,并不适合去修改配置文件,则通过下面这段代码,写是BaseActivity的成员方法,其中稍难的就是如何获取com.android.internal.R$styleable.Window这个stylable,记住$这个符号是等于代码中的“.”反射是需要写成$,stylable其实是R的内部类,获取到这个数组,就可以用反射调用ActivityInfo#isTranslucentOrFloating()这个方法了。
private boolean isTranslucentOrFloating(){
boolean isTranslucentOrFloating = false;
try {
int [] styleableRes = (int[]) Class.forName("com.android.internal.R$styleable").getField("Window").get(null);
final TypedArray ta = obtainStyledAttributes(styleableRes);
Method m = ActivityInfo.class.getMethod("isTranslucentOrFloating", TypedArray.class);
m.setAccessible(true);
isTranslucentOrFloating = (boolean)m.invoke(null, ta);
m.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
return isTranslucentOrFloating;
}
在onCreate的时候,先判断,如果透明,直接把方向改为SCREEN_ORIENTATION_UNSPECIFIED:
@Override
protected void onCreate(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O && isTranslucentOrFloating()) {
boolean result = fixOrientation();
}
super.onCreate(savedInstanceState);
}
private boolean fixOrientation(){
try {
Field field = Activity.class.getDeclaredField("mActivityInfo");
field.setAccessible(true);
ActivityInfo o = (ActivityInfo)field.get(this);
o.screenOrientation = -1;
field.setAccessible(false);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
然后在重写setRequestedOrientation设置方向的时候如果透明,直接不执行:
@Override
public void setRequestedOrientation(int requestedOrientation) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O && isTranslucentOrFloating()) {
return;
}
super.setRequestedOrientation(requestedOrientation);
}
以上就是问题的解决方法,特此记录