Android onConfigurationChanged总结

应用通过 AndroidManifest.xml 中,指定 mcc、mnc、locale、touchscreen、keyboard、keyboardHidden、navigation、orientation、screenLayout、uiMode、screenSize、smallestScreenSize、density、layoutDirection、colorMode、grammaticalGender、fontScale、fontWeightAdjustment 可配置当前activity在接受到对应configurationChange时候不relaunch。

示例如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.miui.home"
    android:sharedUserId="@string/sharedUserId"
    tools:ignore="UniquePermission">
    <application
        android:name="xxxxxxx">
        
        <activity android:name=".MainActivity"
        android:configChanges="screenSize|orientation|keyboard|navigation|keyboardHidden
                               |mcc|mnc|uiMode|smallestScreenSize|screenLayout|colorMode|touchscreen">
        </activity>
	</application>
</manifes>

如上代码可以使得activity在接收到 "screenSize|orientation|keyboard|navigation|keyboardHidden |mcc|mnc|uiMode|smallestScreenSize|screenLayout|colorMode|touchscreen"后不会重新创建,上面的属性都是来自frameworks/base/core/res/res/values/attrs_manifest.xml

对于上述各个属性的解释如下

属性value描述拓展
mcc0x0001移动国家代码:这个是IMSI(International Mobile Subscriber Identity)的Mobile Country Code(MCC)发生了变化。IMSI是SIM卡(Subscriber Identity Module)的标识符,它包括MCC,MNC(Mobile Network Code)和MSIN(Mobile Station International Subscriber Number)。MCC是Mobile Country Code的缩写,它代表移动网络的代码,用于标识一个国家或地区。
默认情况下,从Android O开始,当SIM卡更新了Mobile Country Code(MCC)时,Android不会重新创建活动(Activity)即使应用程序在清单文件中没有指定configChanges。这意味着应用程序的活动不会在MCC变化时自动重新创建
然而,如果应用程序希望在MCC变化时重新创建活动,它可以在清单文件中指定mcc属性在recreateOnConfigChanges中。这样,当MCC发生变化时,Android会重新创建活动。(这一点稍后会说)
O及其以上MCC、MNC默认不在relaunch,如果需要,请自己配置recreateOnConfigChanges;如果希望onConfigurationChanged回调,可以在configChanges配置
mnc0x0002移动网络代码:同上同上
locale0x0004语言区域变化,表示用户更改了显示语言。切换语言此项会改变
touchscreen0x0008触摸屏类型变化,通常不常见。实际开发中折叠屏会发生此项,开机过程中,折叠屏状态没有初始化完成但是桌面已经启动,后面走到display检测逻辑时候,重新检测了屏幕,发现改变了,此项将会回调
keyboard0x0010键盘类型变化,例如连接了外部键盘。
例如,它可能定义了不同的键盘类型,如内置键盘、蓝牙键盘、外部键盘等。当用户插入外部键盘时,系统会检测到这种变化,并可能根据新的键盘类型更新应用程序的某些功能或行为。
例如,如果应用程序依赖于特定的键盘输入方式(如数字键盘或字母键盘),那么当键盘类型改变时,应用程序可能需要更新其界面以适应新的键盘类型。例如,如果用户插入了外部键盘,应用程序可能需要切换到更适合外部键盘的输入界面。
总的来说,这段代码是Android系统中的一部分,用于处理用户插入外部键盘时键盘类型的变化,并根据新的键盘类型更新应用程序的行为。
keyboardHidden0x0020键盘或导航可见性变化,例如滑出或收回物理键盘。
navigation0x0040导航条发生了变化
orientation0x0080设备旋转,横向显示和竖向显示模式切换。
screenLayout0x0100屏幕布局变化,可能是由于激活了不同的显示。
uiMode0x0200用户界面模式变化,例如进入或退出汽车模式、夜间模式等。
screenSize0x0400当前可用屏幕大小变化,例如从竖屏切换到横屏。
smallestScreenSize0x0800物理屏幕大小变化,例如切换到外部显示器。
density0x1000显示密度变化,例如用户调整显示比例或激活不同显示。
layoutDirection0x2000RTL 切换相关;布局方向变化,例如从左到右(LTR)切换到右到左(RTL)。切换RTL生效
colorMode0x4000屏幕色彩模式变化,如色域或动态范围变化。
grammaticalGender0x8000语法性别变化,例如用户在 UI 中设置了语法性别。
fontScale0x40000000全局字体大小缩放发生改变
fontWeightAdjustment0x10000000字体粗细调整,用户增加了字体粗细。

colorMode:

WIDE_COLOR_GAMU:广色域模式,在使用该色域的时候,需要通过isWideColorGamut()方法来判断当前设备是否支持广色域;

namevaluedesc
COLOR_MODE_WIDE_COLOR_GAMUT_MASK0x3广色域位掩码,掩码在代码逻辑中进行位掩码实现所需要的功能
COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED0x0screen未知是否属于广色域模式
COLOR_MODE_WIDE_COLOR_GAMUT_NO0x1非广色域模式
COLOR_MODE_WIDE_COLOR_GAMUT_YES0x2广色域模式
COLOR_MODE_HDR_MASK0xcHDR位掩码
COLOR_MODE_HDR_SHIFT2位移动以获取屏幕动态范围
COLOR_MODE_HDR_UNDEFINED0x0screen未知是否属于HDR
COLOR_MODE_HDR_NO0x1 << COLOR_MODE_HDR_SHIFTscreen不属于HDR
COLOR_MODE_HDR_YES0x2 << COLOR_MODE_HDR_SHIFTscreen属于HDR(动态范围)
COLOR_MODE_UNDEFINEDCOLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED

screenLayout

screenLayout其实是承载着四个配置的:

  • 屏幕大小等级:有SCREENLAYOUT_SIZE_SMALLSCREENLAYOUT_SIZE_NORMALSCREENLAYOUT_SIZE_LARGESCREENLAYOUT_SIZE_XLARGE四种;
  • 是否宽屏:屏幕是否比普通屏幕更宽或更高;
  • 屏幕方向:屏幕是从左向右显示,还是从有向左显示;
  • 是否是圆角屏:屏幕是否有圆角
namevaluedesc
SCREENLAYOUT_SIZE_MASK0x0fSIZE_MASK(屏幕大小)
SCREENLAYOUT_SIZE_UNDEFINED0x00未知大小
SCREENLAYOUT_SIZE_SMALL0x01小(屏幕尺寸小于3英寸左右的布局)
SCREENLAYOUT_SIZE_NORMAL0x02正常(屏幕尺寸小于4.5英寸左右)
SCREENLAYOUT_SIZE_LARGE0x03大(4英寸-7英寸之间)
SCREENLAYOUT_SIZE_XLARGE0x04超大(7-10英寸之间)
SCREENLAYOUT_LONG_MASK0x30LONG_MASK(屏幕纵横比)
SCREENLAYOUT_LONG_UNDEFINED0x00未知宽屏
SCREENLAYOUT_LONG_NO0x10非宽屏
SCREENLAYOUT_LONG_YES0x20宽屏
SCREENLAYOUT_LAYOUTDIR_MASK0xC0LAYOUTDIR_MASK(屏幕方向)
SCREENLAYOUT_LAYOUTDIR_SHIFT6
SCREENLAYOUT_LAYOUTDIR_UNDEFINED0x00未知
SCREENLAYOUT_LAYOUTDIR_LTR0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT屏幕是从左向右显示
SCREENLAYOUT_LAYOUTDIR_RTL0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT屏幕是从右向左显示
SCREENLAYOUT_ROUND_MASK0x300ROUND_MASK(屏幕圆角屏)
SCREENLAYOUT_ROUND_SHIFT8
SCREENLAYOUT_ROUND_UNDEFINED0x00未知
SCREENLAYOUT_ROUND_NO0x1 << SCREENLAYOUT_ROUND_SHIFT非圆角屏
SCREENLAYOUT_ROUND_YES0x2 << SCREENLAYOUT_ROUND_SHIFT圆角屏
SCREENLAYOUT_UNDEFINEDSCREENLAYOUT_SIZE_UNDEFINEDSCREENLAYOUT_LONG_UNDEFINEDSCREENLAYOUT_LAYOUTDIR_UNDEFINEDSCREENLAYOUT_ROUND_UNDEFINED未知
SCREENLAYOUT_COMPAT_NEEDED0x10000000

touchscreen

namevaluedesc
TOUCHSCREEN_UNDEFINED0未知
TOUCHSCREEN_NOTOUCH1非触摸
TOUCHSCREEN_STYLUS2手写笔模式
TOUCHSCREEN_FINGER3手指,支持触摸

keyboard

namevaluedesc
KEYBOARD_UNDEFINED0未知
KEYBOARD_NOKEYS1设备没有用于文本输入的硬按键
KEYBOARD_QWERTY2设备具有标准硬键盘(全键)
KEYBOARD_12KEY3设备具有 12 键硬键盘

keyboardHidden

namevaluedesc
KEYBOARDHIDDEN_UNDEFINED0未知
KEYBOARDHIDDEN_NO1设备具有可用的键盘
KEYBOARDHIDDEN_YES2设备具有可用的键盘,但它处于隐藏状态,且设备没有启用软键盘
KEYBOARDHIDDEN_SOFT3设备已经启用软键盘

hardKeyboardHidden

namevaluedesc
HARDKEYBOARDHIDDEN_UNDEFINED0未知
HARDKEYBOARDHIDDEN_NO1设备具有可用的硬键盘
HARDKEYBOARDHIDDEN_YES2设备具有可用的硬键盘,但它处于隐藏状态
namevaluedesc
NAVIGATION_UNDEFINED0未知
NAVIGATION_NONAV1除了使用触摸屏以外,设备没有其他导航设施
NAVIGATION_DPAD2设备具有用于导航的方向键
NAVIGATION_TRACKBALL3设备具有用于导航的轨迹球
NAVIGATION_WHEEL4设备具有用于导航的方向盘
namevaluedesc
NAVIGATIONHIDDEN_UNDEFINED0未知
NAVIGATIONHIDDEN_NO1导航键可供用户使用
NAVIGATIONHIDDEN_YES2导航键不可用

Orientation

namevaluedesc
ORIENTATION_UNDEFINED0未知
ORIENTATION_PORTRAIT1竖屏方向,屏幕宽度小于高度
ORIENTATION_LANDSCAPE2横屏方向,屏幕宽度大于高度
ORIENTATION_SQUARE3正方形屏幕,认为屏幕宽度等于高度

uiMode

namevaluedesc
UI_MODE_TYPE_MASK0x0f定义了设备的整个UI模式,它支持如下取值
UI_MODE_TYPE_UNDEFINED0x00未知
UI_MODE_TYPE_NORMAL0x01通常模式
UI_MODE_TYPE_DESK0x02带底座模式
UI_MODE_TYPE_CAR0x03车载模式
UI_MODE_TYPE_TELEVISION0x04电视模式
UI_MODE_TYPE_APPLIANCE0x05设备模式(无显示器)
UI_MODE_TYPE_WATCH0x06手表模式
UI_MODE_TYPE_VR_HEADSET0x07
UI_MODE_NIGHT_MASK0x30定义了屏幕是否在一个特殊模式中
UI_MODE_NIGHT_UNDEFINED0x00未知
UI_MODE_NIGHT_NO0x10白天模式
UI_MODE_NIGHT_YES0x20夜间模式

densityDpi

namevaluedesc
DENSITY_DPI_UNDEFINED0
DENSITY_DPI_ANY0xfffe
DENSITY_DPI_NONE0xffff

windowConfiguration

windowConfigurationdesc
mBoundsbounds信息,包括insets
mAppBoundsApp窗口信息,不包括insets
mWindowingMode窗口模式
mDisplayWindowModeDisplay的窗口模式
mActivityTypeActivity类型
mAlwaysOnTop是否要一致处于顶部显示的标志

**recreateOnConfigChanges配置mcc、mnc **

上面说过了默认情况下,从Android O开始,当SIM卡更新了Mobile Country Code(MCC)时,Android不会重新创建活动(Activity)即使应用程序在清单文件中没有指定configChanges。这意味着应用程序的活动不会在MCC变化时自动重新创建

那么如果我们期望应用在接收到MCC、MNC变化是需要重建activity需要怎么做呢?

recreateOnConfigChanges 配置 “mcc|mnc”

例如,如果你希望在移动网络运营商(mcc和mnc)发生变化时重新创建活动,你可以在AndroidManifest.xml文件中添加android:configChanges=“mcc|mnc”。这样,当移动网络运营商发生变化时,系统就会重新创建活动。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.miui.home"
    android:sharedUserId="@string/sharedUserId"
    tools:ignore="UniquePermission">
    <application
        android:name="xxxxxxx">
        
        <activity android:name=".MainActivity"
            android:recreateOnConfigChanges="mcc|mnc">
        </activity>
	</application>
</manifes>