您现在的位置是:首页 > 技术教程 正文

Only fullscreen opaque activities can request orientation

admin 阅读: 2024-03-19
后台-插件-广告管理-内容页头部广告(手机)

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。
专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。
未经允许不得转载

目录

  • 一、导读
  • 二、概览
  • 三、分析
  • 四、 推荐阅读

在这里插入图片描述

一、导读

我们继续总结学习基础知识,温故知新。

本文记录一次bug解决的过程,

Only fullscreen opaque activities can request orientation

二、概览

今天将 targetSdkVersion 的版升级到了29,出现了一些奇怪的报错,日志如下

# main(1) java.lang.IllegalStateException Only fullscreen opaque activities can request orientation 解析原始 java.lang.RuntimeException:Unable to start activity ComponentInfo{com.xxx/com.xyz.QActivity}: java.lang.IllegalStateException: Only fullscreen opaque activities can request orientation android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3303) ...... Caused by: java.lang.IllegalStateException:Only fullscreen opaque activities can request orientation android.app.Activity.onCreate(Activity.java:10811) androidx.core.app.ComponentActivity.void onCreate(android.os.Bundle)(ComponentActivity.java:861) androidx.activity.ComponentActivity.void onCreate(android.os.Bundle)(ComponentActivity.java:3231) androidx.fragment.app.FragmentActivity.void onCreate(android.os.Bundle)(FragmentActivity.java:2731) com.xyz.QActivity.void onCreate(android.os.Bundle)(QActivity.java:518) android.app.Activity.performCreate(Activity.java:7383) android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:11218) android.app.ActivityThread.performLaunchActivity(ActivityThread.java:31256) android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:31411) android.app.ActivityThread.-wrap12(Unknown Source:0) android.app.ActivityThread$H.handleMessage(ActivityThread.java:19194) android.os.Handler.dispatchMessage(Handler.java:1018) android.os.Looper.loop(Looper.java:166) android.app.ActivityThread.main(ActivityThread.java:75129) java.lang.reflect.Method.invoke(Native Method) com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:2145) com.android.internal.os.ZygoteInit.main(ZygoteInit.java:9211)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

这个问题只有8。0的系统才会出现,下面我们一起来分析下原因。

三、分析

报的错误是只有全屏不透明的activity可以设置屏幕方向,那我们先看看activit的设置

<activity android:name="com.xyz.QActivity" android:launchMode="singleTop" android:screenOrientation="portrait" 设置方向 android:theme="@style/TransparentTheme" /> 透明主题
  • 1
  • 2
  • 3
  • 4
  • 5

以上我们设置了两个属性,我们再来看看源码,为什么8.0会报错

protected void onCreate(@Nullable Bundle savedInstanceState) { // 在 onCreate() 方法中会进行屏幕配置检查 // 如果固定屏幕方向,且设置了透明色或者悬浮,则会抛出异常 if (getApplicationInfo().targetSdkVersion > O && mActivityInfo.isFixedOrientation()) { if (isTranslucentOrFloating) { throw new IllegalStateException( "Only fullscreen opaque activities can request orientation"); } } //.... } //ActivityInfo.java /** * 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; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

知道了原因,我们来看看怎么解决问题,其思路是这样的,

  1. 检查是否透明色或者悬浮
  2. 如果有的话就设置屏幕不固定

说大白话就是进onCreate的时候,判断是透明窗口风格,把屏幕朝向改为未指定类型SCREEN_ORIENTATION_UNSPECIFIED,
因为Activity是透明的,所以其方向依赖于父Activity,所以这个改动对结果不会产生任何影响。

那我们怎么判断是否透明呢?答案是反射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); ta.recycle(); m.setAccessible(false); } catch (Exception e) { } return isTranslucentOrFloating; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

那怎么设置方向呢?,答案还是反射

/** * 反射 **/ private static void fixOrientation(Activity activity) { try { Class activityClass = Activity.class; Field mActivityInfoField = activityClass.getDeclaredField("mActivityInfo"); mActivityInfoField.setAccessible(true); ActivityInfo activityInfo = (ActivityInfo) mActivityInfoField.get(activity); // 获取activity 方向是否是固定的 Method isFixedOrientation = ActivityInfo.class.getMethod("isFixedOrientation"); isFixedOrientation.setAccessible(true); // 获取方法的值,即 源码中隐藏的方法 isFixedOrientation() boolean hasFixedOri = (boolean) isFixedOrientation.invoke(activityInfo); isFixedOrientation.setAccessible(false); // 如果是固定方向 if (hasFixedOri) { // 当然我们也可以把判断过程去掉 //设置屏幕不固定 activityInfo.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_BEHIND; } else{ // do nothing } mActivityInfoField.setAccessible(false); } catch (Exception e) { } try { Class activityClass = Activity.class; Field mActivityInfoField = activityClass.getDeclaredField("mActivityInfo"); mActivityInfoField.setAccessible(true); ActivityInfo activityInfo = (ActivityInfo) mActivityInfoField.get(activity); //设置屏幕不固定 activityInfo.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; } catch (Exception e) { } } 下面这个是源码 /** * Returns true if the activity's orientation is fixed. * @hide */ public boolean isFixedOrientation() { return isFixedOrientationLandscape() || isFixedOrientationPortrait() || screenOrientation == SCREEN_ORIENTATION_LOCKED; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

当然,我们还需要进行一次版本的判断

@Override protected void onCreate(@Nullable Bundle savedInstanceState) { //切记:在父类oncreate()方法调用前调用该方法修改配置 if (Build.VERSION.SDK_INT == 26 && isTranslucentOrFloating()) { fixOrientation(this); } super.onCreate(savedInstanceState); } @Override protected void setRequestedOrientation(int requestedOrientation) { // 这里也最好改下,最好是不要让主动进行设置 if (Build.VERSION.SDK_INT == 26 && isTranslucentOrFloating()) { return; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

另外, Orientation 新增了已个behind属性,表示当前的Activity和栈中在它下方的Activity使用相同的方向。建议这里也改一下。

<activity android:name="com.xyz.QActivity" android:launchMode="singleTop" android:screenOrientation="behind" 设置方向 android:theme="@style/TransparentTheme" /> 透明主题
  • 1
  • 2
  • 3
  • 4
  • 5

四、 推荐阅读

Java 专栏

SQL 专栏

数据结构与算法

Android学习专栏

未经允许不得转载

ddd

标签:
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

在线投稿:投稿 站长QQ:1888636

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索