Android8.0適配-Only fullscreen opaque activities can request orientation

風吹過wu發表於2018-11-21

背景

2018年7月18日上午,電信終端產業協會(TAF)釋出《移動應用軟體高API等級預置與分發自律公約》(以下簡稱《公約》)。OPPO、華為、百度、360、阿里、小米、VIVO、騰訊作為發起單位,共同簽署《公約》併發出聯合倡議:號召廣大移動應用軟體預置與分發服務提供者,拒絕上架並及時更新低API等級的應用,共同維護使用者權益。《公約》規定,自2019年5月1日起,新上架和預置應用應基於Android 8.0 (API等級26)及以上開發。自2019年8月1日起,現有應用的更新應基於Android 8.0 (API等級26)及以上開發。

老專案開始做高版本的適配,這不將targetSDK版本改為最新的28,問題不斷,這裡特地做個記錄

異常日誌

Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
                                                     at android.app.Activity.onCreate(Activity.java:1081)
                                                     at android.support.v4.app.BaseFragmentActivityDonut.onCreate(BaseFragmentActivityDonut.java:39)
                                                     at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:278)
                                                     at com.seeyon.mobile.android.model.gesture.activity.BaseGuestureActivity.onCreate(BaseGuestureActivity.java:31)
                                                     at com.seeyon.mobile.android.model.base.BaseActivity.onCreate(BaseActivity.java:83)
                                                     at com.seeyon.mobile.android.model.base.ActionBarBaseActivity.onCreate(ActionBarBaseActivity.java:61)
                                                     at com.seeyon.mobile.android.model.flow.FlowSearchActivity.onCreate(FlowSearchActivity.java:53)
                                                     at android.app.Activity.performCreate(Activity.java:7372)
                                                     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1218)
                                                     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3147)
                                                     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3302) 
                                                     at android.app.ActivityThread.-wrap12(Unknown Source:0) 
                                                     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1891) 
                                                     at android.os.Handler.dispatchMessage(Handler.java:108) 
                                                     at android.os.Looper.loop(Looper.java:166) 
                                                     at android.app.ActivityThread.main(ActivityThread.java:7425) 
                                                     at java.lang.reflect.Method.invoke(Native Method) 
複製程式碼

首先這是google的一個bug,別等修復了,現在9.0了還是有問題。

原始碼

//Need to pay attention mActivityInfo.isFixedOrientation() and ActivityInfo.isTranslucentOrFloating(ta)
    if (getApplicationInfo().targetSdkVersion >= O_MR1 && mActivityInfo.isFixedOrientation()) {
        final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
        final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
        ta.recycle();

        //Exception occurred
        if (isTranslucentOrFloating) {
            throw new IllegalStateException(
                    "Only fullscreen opaque activities can request orientation");
        }
    }
複製程式碼

從上述程式碼,不難看出報錯的原因,就是 isTranslucentOrFloating 的activity不能是固定orientation的

        * Returns true if the activity's orientation is fixed.
        * @hide
        */
        public boolean isFixedOrientation() {
            return isFixedOrientationLandscape() || isFixedOrientationPortrait()
                    || screenOrientation == SCREEN_ORIENTATION_LOCKED;
        }
        /**
        * Returns true if the activity's orientation is fixed to portrait.
        * @hide
        */
        boolean isFixedOrientationPortrait() {
            return isFixedOrientationPortrait(screenOrientation);
        }

        /**
        * Returns true if the activity's orientation is fixed to portrait.
        * @hide
        */
        public static boolean isFixedOrientationPortrait(@ScreenOrientation int orientation) {
            return orientation == SCREEN_ORIENTATION_PORTRAIT
                    || orientation == SCREEN_ORIENTATION_SENSOR_PORTRAIT
                    || orientation == SCREEN_ORIENTATION_REVERSE_PORTRAIT
                    || orientation == SCREEN_ORIENTATION_USER_PORTRAIT;
        }

        /**
        * Determines whether the {@link Activity} is considered translucent or floating.
        * @hide
        */
        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;
        }
複製程式碼

從上面的原始碼中可以知道,解決問題的方法

解決方法

  • 不固定方向

比如去除 android:screenOrientation="portrait",或者不呼叫設定方向的程式碼

  • isTranslucentOrFloating 返回false

    只有android:windowIsTranslucent

<item name="android:windowIsTranslucent">false</item>
複製程式碼
若同時還有windowIsFloating
複製程式碼
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowIsFloating">false</item>
複製程式碼

總結:

這個改動的目的是想阻止非全屏的Activity鎖定螢幕旋轉,因為當前Activity是透明的,浮動的或可滑動取消的,是否鎖屏應該由全屏的Activity決定,而不是並沒有全部佔據螢幕的Activity決定。

相關文章