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 | 描述 | 拓展 |
|---|---|---|---|
| mcc | 0x0001 | 移动国家代码:这个是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配置 |
| mnc | 0x0002 | 移动网络代码:同上 | 同上 |
| locale | 0x0004 | 语言区域变化,表示用户更改了显示语言。 | 切换语言此项会改变 |
| touchscreen | 0x0008 | 触摸屏类型变化,通常不常见。 | 实际开发中折叠屏会发生此项,开机过程中,折叠屏状态没有初始化完成但是桌面已经启动,后面走到display检测逻辑时候,重新检测了屏幕,发现改变了,此项将会回调 |
| keyboard | 0x0010 | 键盘类型变化,例如连接了外部键盘。 例如,它可能定义了不同的键盘类型,如内置键盘、蓝牙键盘、外部键盘等。当用户插入外部键盘时,系统会检测到这种变化,并可能根据新的键盘类型更新应用程序的某些功能或行为。 例如,如果应用程序依赖于特定的键盘输入方式(如数字键盘或字母键盘),那么当键盘类型改变时,应用程序可能需要更新其界面以适应新的键盘类型。例如,如果用户插入了外部键盘,应用程序可能需要切换到更适合外部键盘的输入界面。 总的来说,这段代码是Android系统中的一部分,用于处理用户插入外部键盘时键盘类型的变化,并根据新的键盘类型更新应用程序的行为。 | |
| keyboardHidden | 0x0020 | 键盘或导航可见性变化,例如滑出或收回物理键盘。 | |
| navigation | 0x0040 | 导航条发生了变化 | |
| orientation | 0x0080 | 设备旋转,横向显示和竖向显示模式切换。 | |
| screenLayout | 0x0100 | 屏幕布局变化,可能是由于激活了不同的显示。 | |
| uiMode | 0x0200 | 用户界面模式变化,例如进入或退出汽车模式、夜间模式等。 | |
| screenSize | 0x0400 | 当前可用屏幕大小变化,例如从竖屏切换到横屏。 | |
| smallestScreenSize | 0x0800 | 物理屏幕大小变化,例如切换到外部显示器。 | |
| density | 0x1000 | 显示密度变化,例如用户调整显示比例或激活不同显示。 | |
| layoutDirection | 0x2000 | RTL 切换相关;布局方向变化,例如从左到右(LTR)切换到右到左(RTL)。 | 切换RTL生效 |
| colorMode | 0x4000 | 屏幕色彩模式变化,如色域或动态范围变化。 | |
| grammaticalGender | 0x8000 | 语法性别变化,例如用户在 UI 中设置了语法性别。 | |
| fontScale | 0x40000000 | 全局字体大小缩放发生改变 | |
| fontWeightAdjustment | 0x10000000 | 字体粗细调整,用户增加了字体粗细。 | |
colorMode:
WIDE_COLOR_GAMU:广色域模式,在使用该色域的时候,需要通过isWideColorGamut()方法来判断当前设备是否支持广色域;
| name | value | desc |
|---|---|---|
| COLOR_MODE_WIDE_COLOR_GAMUT_MASK | 0x3 | 广色域位掩码,掩码在代码逻辑中进行位掩码实现所需要的功能 |
| COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED | 0x0 | screen未知是否属于广色域模式 |
| COLOR_MODE_WIDE_COLOR_GAMUT_NO | 0x1 | 非广色域模式 |
| COLOR_MODE_WIDE_COLOR_GAMUT_YES | 0x2 | 广色域模式 |
| COLOR_MODE_HDR_MASK | 0xc | HDR位掩码 |
| COLOR_MODE_HDR_SHIFT | 2 | 位移动以获取屏幕动态范围 |
| COLOR_MODE_HDR_UNDEFINED | 0x0 | screen未知是否属于HDR |
| COLOR_MODE_HDR_NO | 0x1 << COLOR_MODE_HDR_SHIFT | screen不属于HDR |
| COLOR_MODE_HDR_YES | 0x2 << COLOR_MODE_HDR_SHIFT | screen属于HDR(动态范围) |
| COLOR_MODE_UNDEFINED | COLOR_MODE_WIDE_COLOR_GAMUT_UNDEFINED |
screenLayout
screenLayout其实是承载着四个配置的:
- 屏幕大小等级:有
SCREENLAYOUT_SIZE_SMALL、SCREENLAYOUT_SIZE_NORMAL、SCREENLAYOUT_SIZE_LARGE和SCREENLAYOUT_SIZE_XLARGE四种; - 是否宽屏:屏幕是否比普通屏幕更宽或更高;
- 屏幕方向:屏幕是从左向右显示,还是从有向左显示;
- 是否是圆角屏:屏幕是否有圆角
| name | value | desc | |||
|---|---|---|---|---|---|
| SCREENLAYOUT_SIZE_MASK | 0x0f | SIZE_MASK(屏幕大小) | |||
| SCREENLAYOUT_SIZE_UNDEFINED | 0x00 | 未知大小 | |||
| SCREENLAYOUT_SIZE_SMALL | 0x01 | 小(屏幕尺寸小于3英寸左右的布局) | |||
| SCREENLAYOUT_SIZE_NORMAL | 0x02 | 正常(屏幕尺寸小于4.5英寸左右) | |||
| SCREENLAYOUT_SIZE_LARGE | 0x03 | 大(4英寸-7英寸之间) | |||
| SCREENLAYOUT_SIZE_XLARGE | 0x04 | 超大(7-10英寸之间) | |||
| SCREENLAYOUT_LONG_MASK | 0x30 | LONG_MASK(屏幕纵横比) | |||
| SCREENLAYOUT_LONG_UNDEFINED | 0x00 | 未知宽屏 | |||
| SCREENLAYOUT_LONG_NO | 0x10 | 非宽屏 | |||
| SCREENLAYOUT_LONG_YES | 0x20 | 宽屏 | |||
| SCREENLAYOUT_LAYOUTDIR_MASK | 0xC0 | LAYOUTDIR_MASK(屏幕方向) | |||
| SCREENLAYOUT_LAYOUTDIR_SHIFT | 6 | ||||
| SCREENLAYOUT_LAYOUTDIR_UNDEFINED | 0x00 | 未知 | |||
| SCREENLAYOUT_LAYOUTDIR_LTR | 0x01 << SCREENLAYOUT_LAYOUTDIR_SHIFT | 屏幕是从左向右显示 | |||
| SCREENLAYOUT_LAYOUTDIR_RTL | 0x02 << SCREENLAYOUT_LAYOUTDIR_SHIFT | 屏幕是从右向左显示 | |||
| SCREENLAYOUT_ROUND_MASK | 0x300 | ROUND_MASK(屏幕圆角屏) | |||
| SCREENLAYOUT_ROUND_SHIFT | 8 | ||||
| SCREENLAYOUT_ROUND_UNDEFINED | 0x00 | 未知 | |||
| SCREENLAYOUT_ROUND_NO | 0x1 << SCREENLAYOUT_ROUND_SHIFT | 非圆角屏 | |||
| SCREENLAYOUT_ROUND_YES | 0x2 << SCREENLAYOUT_ROUND_SHIFT | 圆角屏 | |||
| SCREENLAYOUT_UNDEFINED | SCREENLAYOUT_SIZE_UNDEFINED | SCREENLAYOUT_LONG_UNDEFINED | SCREENLAYOUT_LAYOUTDIR_UNDEFINED | SCREENLAYOUT_ROUND_UNDEFINED | 未知 |
| SCREENLAYOUT_COMPAT_NEEDED | 0x10000000 |
touchscreen
| name | value | desc |
|---|---|---|
| TOUCHSCREEN_UNDEFINED | 0 | 未知 |
| TOUCHSCREEN_NOTOUCH | 1 | 非触摸 |
| TOUCHSCREEN_STYLUS | 2 | 手写笔模式 |
| TOUCHSCREEN_FINGER | 3 | 手指,支持触摸 |
keyboard
| name | value | desc |
|---|---|---|
| KEYBOARD_UNDEFINED | 0 | 未知 |
| KEYBOARD_NOKEYS | 1 | 设备没有用于文本输入的硬按键 |
| KEYBOARD_QWERTY | 2 | 设备具有标准硬键盘(全键) |
| KEYBOARD_12KEY | 3 | 设备具有 12 键硬键盘 |
keyboardHidden
| name | value | desc |
|---|---|---|
| KEYBOARDHIDDEN_UNDEFINED | 0 | 未知 |
| KEYBOARDHIDDEN_NO | 1 | 设备具有可用的键盘 |
| KEYBOARDHIDDEN_YES | 2 | 设备具有可用的键盘,但它处于隐藏状态,且设备没有启用软键盘 |
| KEYBOARDHIDDEN_SOFT | 3 | 设备已经启用软键盘 |
hardKeyboardHidden
| name | value | desc |
|---|---|---|
| HARDKEYBOARDHIDDEN_UNDEFINED | 0 | 未知 |
| HARDKEYBOARDHIDDEN_NO | 1 | 设备具有可用的硬键盘 |
| HARDKEYBOARDHIDDEN_YES | 2 | 设备具有可用的硬键盘,但它处于隐藏状态 |
navigation
| name | value | desc |
|---|---|---|
| NAVIGATION_UNDEFINED | 0 | 未知 |
| NAVIGATION_NONAV | 1 | 除了使用触摸屏以外,设备没有其他导航设施 |
| NAVIGATION_DPAD | 2 | 设备具有用于导航的方向键 |
| NAVIGATION_TRACKBALL | 3 | 设备具有用于导航的轨迹球 |
| NAVIGATION_WHEEL | 4 | 设备具有用于导航的方向盘 |
navigationHidden
| name | value | desc |
|---|---|---|
| NAVIGATIONHIDDEN_UNDEFINED | 0 | 未知 |
| NAVIGATIONHIDDEN_NO | 1 | 导航键可供用户使用 |
| NAVIGATIONHIDDEN_YES | 2 | 导航键不可用 |
Orientation
| name | value | desc |
|---|---|---|
| ORIENTATION_UNDEFINED | 0 | 未知 |
| ORIENTATION_PORTRAIT | 1 | 竖屏方向,屏幕宽度小于高度 |
| ORIENTATION_LANDSCAPE | 2 | 横屏方向,屏幕宽度大于高度 |
| ORIENTATION_SQUARE | 3 | 正方形屏幕,认为屏幕宽度等于高度 |
uiMode
| name | value | desc |
|---|---|---|
| UI_MODE_TYPE_MASK | 0x0f | 定义了设备的整个UI模式,它支持如下取值 |
| UI_MODE_TYPE_UNDEFINED | 0x00 | 未知 |
| UI_MODE_TYPE_NORMAL | 0x01 | 通常模式 |
| UI_MODE_TYPE_DESK | 0x02 | 带底座模式 |
| UI_MODE_TYPE_CAR | 0x03 | 车载模式 |
| UI_MODE_TYPE_TELEVISION | 0x04 | 电视模式 |
| UI_MODE_TYPE_APPLIANCE | 0x05 | 设备模式(无显示器) |
| UI_MODE_TYPE_WATCH | 0x06 | 手表模式 |
| UI_MODE_TYPE_VR_HEADSET | 0x07 | |
| UI_MODE_NIGHT_MASK | 0x30 | 定义了屏幕是否在一个特殊模式中 |
| UI_MODE_NIGHT_UNDEFINED | 0x00 | 未知 |
| UI_MODE_NIGHT_NO | 0x10 | 白天模式 |
| UI_MODE_NIGHT_YES | 0x20 | 夜间模式 |
densityDpi
| name | value | desc |
|---|---|---|
| DENSITY_DPI_UNDEFINED | 0 | |
| DENSITY_DPI_ANY | 0xfffe | |
| DENSITY_DPI_NONE | 0xffff |
windowConfiguration
| windowConfiguration | desc |
|---|---|
| mBounds | bounds信息,包括insets |
| mAppBounds | App窗口信息,不包括insets |
| mWindowingMode | 窗口模式 |
| mDisplayWindowMode | Display的窗口模式 |
| mActivityType | Activity类型 |
| 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>