Only fullscreen opaque activities can request orientation

接手公司的项目,升级sdk之后 ,遇到了这个问题。
参考https://blog.csdn.net/starry_eve/article/details/82777160

如日志所说的,只有全屏且不透明的activity才能请求屏幕方向
想解决问题,需要先明白下面两个问题:

1.全屏不透明的activity如何定义?

在activity的主题配置文件中,声明了下面三者之一的属性,即被定义为 全屏非透明

 <style name="TranslucentOrFloatingTheme" parent="Theme.AppCompat.Light">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowSwipeToDismiss">true</item>
    </style>
2.请求屏幕方向的操作在activity是具体是怎么实现的?

有两种方式:
1)在manifest 文件中声明了activity其屏幕方向

    android:screenOrientation="portrait" 
  1. 在java代码中手动设置
	onCreate(){
		...
 	   requestedOrientation=ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
解决思路

按日志所说的去做就好了…
若是activity主题配置了满足全屏非透明的样式,就不要让该activity请求屏幕方向了。

理解这个bug的来源:
开启多窗口之后,会有多个activity浮动于同一个屏幕,假设多个activity都请求控制屏幕旋转方向,那么屏幕方向到底该由谁做主呢?
想想就很混乱吧
因为Android新版sdk26出了一个规定,屏幕旋转方向只有那些全屏非透明的Activity来决定,在多窗口的情况下,应该有其底部的全屏的activity来决定屏幕旋转方向。

解决方案

一般情况下,我们不会去改动activity非全屏的需求,而是去掉activity请求屏幕旋转的逻辑,让其适应父activity屏幕旋转方向。
由于请求屏幕旋转的逻辑有两个,所以两种情况都要判断去除。

具体思路:

  1. 在公用的基类中,在加载配置文件后,在应用配置创建Activity前,判断是否是非全屏
  2. 使用反射修改ActivityInfo中的属性ScreenOrientation,即忽略掉manifest中的屏幕旋转方向的配置(注意要在该配置被应用前修改)
  3. 重写setRequestedOrientation()方法,若是符合非全屏情况,直接截断,即忽略子Activity中代码请求屏幕旋转方向。

在统一的基础类中加入相应的处理逻辑。

abstract class BaseAct : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O && isTranslucentOrFloating()) {
            val result = fixOrientation()
            Log.d("wolf", "onCreate fixOrientation when Oreo, result=$result")
        }
        super.onCreate(savedInstanceState)
    }

    //去除代码中请求屏幕旋转方向的情况
    override fun setRequestedOrientation(requestedOrientation: Int) {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O && isTranslucentOrFloating()) {
            Log.d("wolf", "avoid calling setRequestOrientation when Oren and is not fullScreen")
            return
        }
        super.setRequestedOrientation(requestedOrientation)
    }
    //去除配置中请求屏幕旋转的情况
    private fun fixOrientation(): Boolean {
        try {
            val field = Activity::class.java.getDeclaredField("mActivityInfo")
            field.isAccessible = true
            val activityInfo = field.get(this) as ActivityInfo
            activityInfo.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
            field.isAccessible = false
            return true
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }
    //判断activity是不是符合全屏非透明
    private fun isTranslucentOrFloating(): Boolean {
        var isTranslucentOrFloating = false
        try {
            val styleRes =
                Class.forName("com.android.internal.R${'$'}styleable").getField("Window").get(null) as IntArray
            val typeArray = obtainStyledAttributes(styleRes)
            val method = ActivityInfo::class.java.getMethod("isTranslucentOrFloating", TypedArray::class.java)
            method.isAccessible = true
            isTranslucentOrFloating = method.invoke(null, typeArray) as Boolean
            method.isAccessible = false
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return isTranslucentOrFloating
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值