当前位置:   article > 正文

【已解决】java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation

java.lang.illegalstateexception: only fullscreen opaque activities can reque

一、开发现场:

       开发中使用activity作为二级界面弹出,且设置了透明主题

二,崩溃日志:

Caused by: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation
        at android.app.Activity.onCreate(Activity.java:986)
        at com.xx.xxx.xxxx.activity.BaseActivity.onCreate(BaseActivity.java:43)
        at com.xx.xxx.xxxx.activity.XxxActivity.onCreate(XxxActivity.java:71)
        at android.app.Activity.performCreate(Activity.java:6975)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) 
        at android.app.ActivityThread.-wrap11(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) 
        at android.os.Handler.dispatchMessage(Handler.java:105) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6541) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 

三、分析原因:

Only fullscreen opaque activities can request orientation  即:只有全屏不透明的activity可以设置orientation

而这个原因是只有8.0上才出现,8.1是已经修复了这个问题的。

本人开发中,是设置了activity的方向是横向,且设置了activity的主题是透明的。

<activity
    android:name=".activity.XxxActivity"
    android:configChanges="keyboardHidden|orientation|screenSize"
    android:screenOrientation="landscape"
    android:windowSoftInputMode="adjustPan|stateHidden"
    android:theme="@style/Theme.Custom.Fullscreen.Transparent" />

所以不能使用网上的解决方案,干掉方向或者透明主题其中一个,只能选择第三种方法,看看如何在兼容两者的情况下去hook绕过该方向检查,不需要修改xml的配置。

看一下8.0系统的Activity源代码:

  1. @MainThread
  2. @CallSuper
  3. protected void onCreate(@Nullable Bundle savedInstanceState) {
  4. if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
  5. if (getApplicationInfo().targetSdkVersion > O && mActivityInfo.isFixedOrientation()) {
  6. final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
  7. final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
  8. ta.recycle();
  9. if (isTranslucentOrFloating) {
  10. throw new IllegalStateException(
  11. "Only fullscreen opaque activities can request orientation");
  12. }
  13. }
  14. //省略部分源代码....
  15. }
  16. //查看ActivityInfo的isTranlucentOrFloating()方法
  17. /**
  18. * Determines whether the {@link Activity} is considered translucent or floating.
  19. * @hide
  20. */
  21. public static boolean isTranslucentOrFloating(TypedArray attributes) {
  22. final boolean isTranslucent =
  23. attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
  24. false);
  25. final boolean isSwipeToDismiss = !attributes.hasValue(
  26. com.android.internal.R.styleable.Window_windowIsTranslucent)
  27. && attributes.getBoolean(
  28. com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
  29. final boolean isFloating =
  30. attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating,
  31. false);
  32. return isFloating || isTranslucent || isSwipeToDismiss;
  33. }

在onCreate()方法中会进行屏幕配置检查。如果固定屏幕方向,且设置了透明色或者悬浮,则会抛出异常。

四、解决方案:

原因基本确定,那么可以考虑是否通过hook反射的方式进行配置的修改,从而绕过检查

  1. @Override
  2. protected void onCreate(@Nullable Bundle savedInstanceState) {
  3. //切记:在父类oncreate()方法调用前调用该方法修改配置
  4. if (Build.VERSION.SDK_INT == 26 && isTranslucentOrFloating()) {
  5. fixOrientation(this);
  6. }
  7. super.onCreate(savedInstanceState);
  8. }
  9. /**
  10. * hook反射方向检查
  11. **/
  12. private static void fixOrientation(Activity activity) {
  13. try {
  14. Class activityClass = Activity.class;
  15. Field mActivityInfoField = activityClass.getDeclaredField("mActivityInfo");
  16. mActivityInfoField.setAccessible(true);
  17. ActivityInfo activityInfo = (ActivityInfo) mActivityInfoField.get(activity);
  18. //设置屏幕不固定
  19. activityInfo.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
  20. } catch (Exception e) {
  21. }
  22. }
  23. /**
  24. * hook反射检查是否透明色或者悬浮
  25. **/
  26. private boolean isTranslucentOrFloating() {
  27. boolean isTranslucentOrFloating = false;
  28. try {
  29. int[] styleableRes = (int[]) Class.forName("com.android.internal.R$styleable").getField("Window").get(null);
  30. final TypedArray typedArray = obtainStyledAttributes(styleableRes);
  31. Method method = ActivityInfo.class.getMethod("isTranslucentOrFloating", TypedArray.class);
  32. method.setAccessible(true);
  33. isTranslucentOrFloating = (boolean) method.invoke(null, typedArray);
  34. method.setAccessible(false);
  35. } catch (Exception e) {
  36. }
  37. return isTranslucentOrFloating;
  38. }

到此,问题基本解决,总结一下:

1,解题思路:hook判断是否透明色或者悬浮,hook修改activity的屏幕方向为不固定,绕过检查。

2,解题模型:查看日志,锁定位置;查看源代码,分析原因;没有思路可对比&参考解决思路,有思路则直接hook实现;归档总结,避免重复犯错;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/375885
推荐阅读
相关标签
  

闽ICP备14008679号