出现的异常:
Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{cn.glority.receipt/cn.glority.receipt.wxapi.WXEntryActivity}: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2858)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2933)
at android.app.ActivityThread.-wrap11(Unknown Source)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1612)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6710)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:770)
出现的位置是微信SDK的回调Activity,之前它在Manifest中的定义是:
<activity
android:name="cn.glority.receipt.wxapi.WXEntryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
基本的意思是说,“fullscreen”为否的activity是不能锁定orientation的,否则抛出异常。
如果一个Activity的Style符合下面三个条件之一,认为不是“fullscreen”:
“windowIsTranslucent”为true;
“windowIsTranslucent”为false,但“windowSwipeToDismiss”为true;
“windowIsFloating“为true;
这个限制的目的是想阻止非全屏的Activity锁定屏幕旋转,因为当前Activity是透明的,浮动的或可滑动取消的,是否锁屏应该由全屏的Activity决定,而不是并没有全部占据屏幕的Activity决定。
这个问题貌似在最新的SDK中已经修复,我们在API Level 27的设备上已经无法重现,但我们手头的API Level 26的设备还是能重现。而且根据上面的代码来看,如果想保留当前Activity的style,“isTranslucentOrFloating”的逻辑根本没法绕过,所以想绕开很难,目前能想到的大概两个方向:
- 推迟SDK升级,等官方修复被大多数设备采用;
- 升级SDK,但重构一下代码,看看已有的非“fullscreen” Activity是不是都是必要的,例如用Fragment实现周围半透明效果,能不能直接把Fragment加入到当前Activity(当然Detach Fragment是有重绘View的开销的)。
我这里的解决方式是:
- 把
<item name="android:windowIsTranslucent">true</item>
换成<item name="android:windowIsTranslucent">false</item>
- 移除manifest中的
android:screenOrientation="portrait"