本文正在参加「金石计划」

前言

前几天多名用户反应同一个问题,在小新平板上无法上网课,点击上课按钮后就退回到主页了。同事了解了一下发现小新平板现在销量特别好,于是赶紧申请了一台测验机打算看看到底是什么问题。

最终同事发现是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应该就能够了,可是官方在这儿有一个提示,如下:

横竖屏切换导致页面频繁重启?详细解读 screenLayout

官方主张在设置orientation的一起设置screenSizescreenLayoutscreenSize我么能够了解,反正屏切换时宽高会交流,那么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_LARGESCREENLAYOUT_SIZE_XLARGE四种
  • 是否宽屏:屏幕是否比普通屏幕更宽或更高
  • 屏幕方向:屏幕是从左向右显现,仍是从有向左显现
  • 是否是圆角屏:屏幕是否有圆角

经过将screenLayout于对应mask进行与运算就能够得到当时屏幕在该特点的值,比如:

screenLayout & SCREENLAYOUT_SIZE_MASK

就能够得到屏幕巨细等级,必定是SCREENLAYOUT_SIZE_SMALL, SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_LARGESCREENLAYOUT_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,因为其他两个特点orientationscreenSize都增加了。

小新平板

那么为什么小新平板上会有不同的现象,在android:configChanges中增加screenLayout完后我在onConfigurationChanged函数中debug获取screenLayout值,发现横屏和竖屏这个值是不同的,分别是268435812和268435796。

经过与mask运算获取四个特点后对比发现,反正屏切换后SCREENLAYOUT_LONG_NO变成了SCREENLAYOUT_LONG_YES,所以没增加screenLayout的时分就会导致Activity重启,增加后就能够了。

至于为什么重启Activity会导致回退到主页,其实是用户表述问题,现象是使用重启了。为什么使用会重启,这是因为咱们的使用架构是单Activity的,页面由fragment承载。当从详情页翻开上课页面时,会经过代码手动将竖屏切换到横屏(一起为了返回详情页时换回竖屏,在详情页手动切换回竖屏)。这时分Activity重启并以横屏状况康复所有fragment,可是康复详情页时分,又切换到竖屏,所以又重启;然后以竖屏状况康复到上课页面,又进行了切换,于是死循环,最终体系将使用重启。

总结

一直以来对android:configChanges没有深入了解,正好趁着这个机会了解了一番,大家今后必定要注意这儿,特别注意官方文档的提示,很重要。