横竖屏切换导致页面频繁重启screenLayout解析
作者:BennuCTech 发布时间:2021-06-14 05:16:22
前言
前几天多名用户反馈同一个问题,在小新平板上无法上网课,点击上课按钮后就退回到首页了。同事了解了一下发现小新平板现在销量特别好,于是赶紧申请了一台测试机打算看看到底是什么问题。
最后同事发现是screenLayout的问题,在manifest中为需要横竖屏切换的Acitivty配置screenLayout即可,如下:
<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
android:launchMode="singleTask">
<intent-filter>
...
</intent-filter>
</activity>
我们之前android:configChanges配置是orientation|keyboardHidden|screenSize
,缺少了screenLayout。
但是为什么在其他设备上没问题,唯独在小新平板上有问题呢?而且为什么添加了screenLayout就解决问题了,这其中的原理是什么?我非常好奇,于是自己研究了一下。
android:configChanges
首先我们要知道android:configChanges
这个配置的作用,这里我们来看看官方的介绍:
列出 Activity 将自行处理的配置变更。在运行时发生配置变更时,默认情况下会关闭 Activity 并将其重启,但使用该属性声明配置将阻止 Activity 重启。相反,Activity 会保持运行状态,并且系统会调用其 onConfigurationChanged() 方法。
当Activity的配置发生变更时(如横竖屏切换),如果在android:configChanges中没有添加该配置,那么就会关闭并重启Activity,这时候debug会发现重新执行了onCreate。但是当我们添加了该配置,如果该配置发生变更,则不会重启Activity,会调用onConfigurationChanged()方法。
那么orientation
就是对应着横竖屏切换,keyboardHidden
则是软键盘弹出,screenSize
则是屏幕尺寸改变。这么来看我们设置了orientation
应该就可以了,但是官方在这里有一个提示,如下:
官方建议在设置orientation
的同时设置screenSize
和screenLayout
,screenSize
我么可以理解,横竖屏切换时宽高会交换,那么screenLayout
是指什么呢?
screenLayout
前面我们知道存在配置时会执行onConfigurationChanged(),这个函数的参数是Configuration
类型的,这个类里保存着Activity的配置,我们来看看对screenLayout
这个属性的描述:
/**
Bit mask of overall layout of the screen. Currently there are four fields:
The SCREENLAYOUT_SIZE_MASK bits define the overall size of the screen.
They may be one of SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_NORMAL,
SCREENLAYOUT_SIZE_LARGE, or SCREENLAYOUT_SIZE_XLARGE.
The SCREENLAYOUT_LONG_MASK defines whether the screen is wider/taller than normal.
They may be one of SCREENLAYOUT_LONG_NO or SCREENLAYOUT_LONG_YES.
The SCREENLAYOUT_LAYOUTDIR_MASK defines whether the screen layout is either LTR or RTL.
They may be one of SCREENLAYOUT_LAYOUTDIR_LTR or SCREENLAYOUT_LAYOUTDIR_RTL.
The SCREENLAYOUT_ROUND_MASK defines whether the screen has a rounded shape.
They may be one of SCREENLAYOUT_ROUND_NO or SCREENLAYOUT_ROUND_YES.
See Supporting Multiple Screens for more information.
**/
public int screenLayout;
可以看到screenLayout其实是承载着四个配置的:
屏幕大小等级:有
SCREENLAYOUT_SIZE_SMALL
,SCREENLAYOUT_SIZE_NORMAL
,SCREENLAYOUT_SIZE_LARGE
和SCREENLAYOUT_SIZE_XLARGE
四种是否宽屏:屏幕是否比普通屏幕更宽或更高
屏幕方向:屏幕是从左向右显示,还是从有向左显示
是否是圆角屏:屏幕是否有圆角
通过将screenLayout于对应mask进行与运算就可以得到当前屏幕在该属性的值,比如:
screenLayout & SCREENLAYOUT_SIZE_MASK
就可以得到屏幕大小等级,一定是SCREENLAYOUT_SIZE_SMALL
, SCREENLAYOUT_SIZE_NORMAL
, SCREENLAYOUT_SIZE_LARGE
和SCREENLAYOUT_SIZE_XLARGE
之一。
四个mask对应的二进制分别是:
SCREENLAYOUT_SIZE_MASK: 0000 0000 1111
SCREENLAYOUT_LONG_MASK: 0000 0011 0000
SCREENLAYOUT_LAYOUTDIR_MASK:0000 1100 0000
SCREENLAYOUT_ROUND_MASK: 0011 0000 0000
比如在我的测试机上得到的screenLayout是268435810,转成二进制就是
0001 0000 0000 0000 0000 0001 0110 0010
通过与四个mask分别计算得到SCREENLAYOUT_SIZE_NORMAL、SCREENLAYOUT_LONG_NO、SCREENLAYOUT_LAYOUTDIR_LTR和SCREENLAYOUT_ROUND_NO
而且无论横屏还是竖屏,我的测试机的screenLayout是不变的,所以即使在android:configChanges
中没用添加screenLayout,横竖屏切换的时候也不会重启Activity,因为其他两个属性orientation
和screenSize
都添加了。
小新平板
那么为什么小新平板上会有不同的现象,在android:configChanges
中添加screenLayout完后我在onConfigurationChanged
函数中debug获取screenLayout值,发现横屏和竖屏这个值是不同的,分别是268435812和268435796。
通过与mask运算获取四个属性后对比发现,横竖屏切换后SCREENLAYOUT_LONG_NO变成了SCREENLAYOUT_LONG_YES,所以没添加screenLayout的时候就会导致Activity重启,添加后就可以了。
至于为什么重启Activity会导致回退到首页,其实是用户表述问题,现象是应用重启了。为什么应用会重启,这是因为我们的应用架构是单Activity的,页面由fragment承载。当从详情页打开上课页面时,会通过代码手动将竖屏切换到横屏(同时为了返回详情页时换回竖屏,在详情页手动切换回竖屏)。这时候Activity重启并以横屏状态恢复所有fragment,但是恢复详情页时候,又切换到竖屏,所以又重启;然后以竖屏状态恢复到上课页面,又进行了切换,于是死循环,最后系统将应用重启。
来源:https://juejin.cn/post/7210212440671387703


猜你喜欢
- 1. 常规使用请求一个权限,然后接收结果回调HoloPermission.with(this,Manifest.permission.WRI
- 在AndroidManifest.xml中加入下面这段话后,<provider android
- JWT简介Json Web Token(JWT):JSON网络令牌,是为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准((RF
- 以前,如果我们希望构建支持foreach枚举的自定义集合,只能实现IEnumerable接口(可能还有IEnumerator()),返回值还
- 有时候我们在阅读PDF文档时会遇到这样一种情况:PDF文档页数比较多,但是又没有书签,所以我们不能根据书签快速了解文档所讲解的内容,也不能点
- 出于安全考虑,在后台与前台进行数据传输时,往往不会直接传输实体模型,而是使用Dto(Data transfer object 数据传输对象)
- 面试题1:说一下抽象类和接口有哪些区别?正经回答:抽象类和接口的主要区别:从设计层面来说,抽象类是对类的抽象,是一种模板设计;接口是行为的抽
- Spring boot项目结合docker容器用,打了个jar包,启动的时候竟然说:no main manifest attribute,
- mybatis输出SQL格式化通过第三方日志工具可以控制日志级别的输出,但是我们发现mybatis输出的SQL不是那么的完整,我们SQL里的
- Java的动态绑定所谓的动态绑定就是指程执行期间(而不是在编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。java继承
- 1.ACSII码加密//ACSII码加密 private static string
- JdbcTypeInterceptor运行时自动添加 jdbcType 属性 * 签名@Intercepts({
- import java.io.BufferedReader;import java.io.InputStreamReader;import
- 本文实例为大家分享了unity实现虚拟摇杆控的具体代码,供大家参考,具体内容如下using UnityEngine;using UnityE
- JVM内部结构图Java虚拟机主要分为五个区域:方法区、堆、Java栈、PC寄存器、本地方法栈。下面来看一些关于JVM结构的重要问题。1.哪
- 实践过程效果代码class BaseClass{ public class Win32
- 面试中可能会被问到为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?Java 创建线程的方法实际
- 题外话:发现好久都没有上来写博文了,毕业设计加上公司暂时没有Android的项目做,只能去自学web上的知识,摸爬打滚到现在,花了一个多月时
- 最近在做项目的时候发现,微服务使用feign相互之间调用时,存在session丢失的问题。例如,使用Feign调用某个远程API,这个远程A
- 1.注解声明:通过@interface就可以声明一个注解。@Target(ElementType.FIELD)@Retention(Rete