赞
踩
错误是由全屏透明 Activity 引起的
Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
手机是 华为荣耀8 Android 8.0
当时,为了解决不显示引导页,直接进入应用时,会闪屏的问题,引入了透明 Activity 样式
<style name="GuideActivityStyle" parent="ImmersionStatusBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
当一个 Activity 固定方向并且是透明的,在8.0以后的版本中就会抛出异常。源码如下
Entry ent = AttributeCache.instance().get(packageName,realTheme, com.android.internal.R.styleable.Window, userId);
final boolean translucent = ent != null && (ent.array.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent, false)|| (!ent.array.hasValue(
com.android.internal.R.styleable.Window_windowIsTranslucent) && ent.array.getBoolean(com.android.internal.R.styleable.Window_windowSwipeToDismiss,false)));
fullscreen = ent != null && !ent.array.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
fullscreen = ent != null && !ActivityInfo.isTranslucentOrFloating(ent.array);
noDisplay = ent != null && ent.array.getBoolean(com.android.internal.R.styleable.Window_windowNoDisplay, false);
if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen && appInfo.targetSdkVersion > O) {
throw new IllegalStateException("Only fullscreen activities can request orientation");
}
可以看出当 三个条件同时满足的时候,系统会抛出"Only fullscreen activities can request orientation"异常。
所幸的是在 Android 9.0 的时候,已经删掉了这个限制了
<style name="GuideActivityStyle" parent="ImmersionStatusBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
<item name="android:windowBackground">@null</item>
</style>
<style name="SplashTheme" parent="AppTheme">
<item name="android:windowBackground">@drawable/shape_launch</item>
<item name="android:windowFullscreen">true</item>
</style>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<item android:drawable="@android:color/white"/>
<item>
<bitmap
android:src="@mipmap/main_splash_bg"
android:gravity="fill" />
</item>
</layer-list>
用了上面的方案,能解决部分手机兼容性问题。但上线之后,依旧有客户反馈,使用微信登录会导致闪退
2020-05-06 03:25:18 A/UncaughtException: ************************************************** Manufacturer: vivo, Model: vivo X9s L, API 27 PackageName: com.xxx.yyy.zzz VersionName: 3.4.3, VersionCode: 91 java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at d.l.a.h.i(FragmentManagerImpl.java:3) at d.l.a.h.c(FragmentManagerImpl.java:36) at d.l.a.h.b(FragmentManagerImpl.java:38) at d.l.a.a.c(BackStackRecord.java:6) at com.xxx.yyy.zzz.activity.MainActivity.a(MainActivity.java:7) at g.l.a.a.a.b.run(Unknown Source:4) at android.os.Handler.handleCallback(Handler.java:790) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:192) at android.app.ActivityThread.main(ActivityThread.java:6866) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:817) **************************************************
谷歌在安卓8.0版本时为了支持全面屏,增加了一个限制:如果是透明的Activity,则不能固定它的方向,因为它的方向其实是依赖其父Activity的(因为透明)。
这个bug只有在8.0中有,8.1中已经修复。具体crash有两种:
如果进onCreate的时候,如果判断是透明窗口风格,直接把屏幕朝向改为未指定类型即SCREEN_ORIENTATION_UNSPECIFIED就可以了,因为Activity是透明的,所以其方向依赖于父Activity,所以这个改动对结果不会产生任何影响。
至于很多透明Activity的代码中调用setRequestedOrientation,更好处理,项目不是有BaseActivity吗,我们直接判断如果是androidO版本,我们不调用它即可,结果也是等效的。
代码如下
public class BaseActivity extends FragmentActivity { private static final String TAG = "BaseActivity"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { if(needCheckOrientation()) { boolean fixOrientation = fixOrientation(); Log.i(TAG, "onCreate fixOrientation when Oreo, result = " + fixOrientation); } super.onCreate(savedInstanceState); } private boolean needCheckOrientation() { return Build.VERSION.SDK_INT == Build.VERSION_CODES.O && isTranslucentOrFloating(); } @Override public void setRequestedOrientation(int requestedOrientation) { if(needCheckOrientation()) { Log.i(TAG, "setRequestedOrientation avoid calling setRequestedOrientation when Oreo"); return; } super.setRequestedOrientation(requestedOrientation); } 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; } 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; } }
然后微信的 WXEntryActivity 再集成 BaseActivity,最终修复 BUG
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。