望远山,知近路,而后自得其乐!

Activity处理配置变更

1. Android系统配置变更

当设备的某些配置可能会在运行时发生变化(例如屏幕方向、键盘可用性,以及当用户启用多窗口模式时)。发生这种变化时,Android 会重启正在运行的 Activity(先后调用 onDestroy()onCreate()。重启行为旨在通过利用与新设备配置相匹配的备用资源来自动重新加载您的应用,从而帮助它适应新配置。

对于此类情况,当Activity被重启时,如何来恢复相关的状态呢?系统为此提供了相应的恢复机制,提供了两个重要的回调函数onSaveInstanceState()onRestoreInstanceState()onSaveInstanceState()函数在onStop执行之后会被执行,而且是每次都会被执行;但onRestoreInstanceState()只有在activity被重启的状态下,才会在onStart之后被调用。

因此,当系统配置发生变化时,前台Activity的会立即被重启,经历的生命周期如下:

onPause -> onStop -> onSaveInstanceState -> onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume

后台的Activity在系统配置发生变化时不会有任何生命周期变化,但当再次进入到该Activity时,如从Acitivity1进入Activity2,在Activity2时系统配置发生变化,Activity2会重启,此时如果按返回键返回Activity1,那么Activity1此时就会销毁之前的实例,重新创建一个新的Activity。当系统配置发生变化之后,后台未被销毁的Activity被切到前台时经理的生命周期如下:

onDestroy -> onCreate -> onStart -> onRestoreInstanceState -> onResume

按照Android系统界面状态保存机制,针对系统配置变更引起的Activity重启情况,需要在onSaveInstanceState函数中将必要的状态数据进行保存,当Activity重启后,在onRestoreInstanceState函数进行恢复。

2.自行处理配置变更

上面的介绍中介绍了当系统配置发生变化时,Activity的处理方式。然而在一些情况下,如果应用在特定配置变更期间无需更新资源,或者开发者并不希望当系统的一些配置发生变化时由系统主动来重启Activity,亦或者因性能限制需要尽量避免 Activity 重启,此等情况,开发者则可声明 Activity 自行处理配置变更,从而阻止系统重启 Activity。

注意:自行处理配置变更可能会提高使用备用资源的难度,因为系统不会为您自动应用这些资源。只有在必须避免 Activity 因配置变更而重启的无奈情况下,您才可考虑使用此方法,并且不建议对大多数应用使用此方法。

如要声明由 Activity 自行处理配置变更,则需要在清单文件中编辑相应的 <activity> 元素,增加并配置 android:configChanges 属性,该属性的值表示要处理的配置。android:configChanges 属性文档中列出该属性的可能值。最常用的值包括 "orientation"、"screenSize" 和 "keyboardHidden"等。

例如,以下清单文件代码所声明的 Activity 可同时处理屏幕方向变更和键盘可用性变更:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

现在,即便其中某个配置发生变化,MyActivity 也不会重启。但 MyActivity 会接收到 onConfigurationChanged()回调方法。此方法会收到传递的 Configuration 对象,从而指定新的设备配置。可以通过读取 Configuration 中的字段确定新配置,然后通过更新界面所用资源进行适当的更改。调用此方法时,Activity 的 Resources 对象会相应地进行更新,并根据新配置返回资源,以便在系统不重启 Activity 的情况下轻松重置界面元素。

例如,以下 onConfigurationChanged() 方法实现了检查当前的设备方向变化:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks the orientation of the screen
    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
        Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
    }
}

Configuration 对象代表所有当前配置,而不仅仅是已变更的配置。多数情况下,您并不在意配置具体发生了哪些变更,而且您可以轻松地重新分配所有资源,为正在处理的配置提供备用资源。例如,由于 Resources 对象现已更新,您便可通过 setImageResource() 重置任何 ImageView,并使用合适的新配置资源。

3. android:configChanges

该属性用于列出 Activity 将自行处理的配置变更项。在运行时发生配置变更时,默认情况下会关闭 Activity 并将其重启,但使用该属性声明配置将阻止 Activity 重启,但相应的变化会通过Activity的onConfigurationChanged() 回调方法进行通知。

任何或所有下列字符串均是该属性的有效值。若有多个值,则使用|进行分隔,例如“locale|navigation|orientation”。

描述
density显示密度发生变更 — 用户可能已指定不同的显示比例,
或者有不同的显示现处于活跃状态。此项为 API 级别 24 中的新增配置
fontScale字体缩放系数发生变更 — 用户已选择新的全局字号。
keyboard键盘类型发生变更 — 例如,用户插入外置键盘。
keyboardHidden键盘无障碍功能发生变更 — 例如,用户显示硬键盘。
layoutDirection布局方向发生变更 — 例如,自从左至右 (LTR) 更改为从右至左 (RTL)。
此项为 API 级别 17 中的新增配置
locale语言区域发生变更 — 用户已为文本选择新的显示语言。
mccIMSI 移动设备国家/地区代码 (MCC) 发生变更 — 检测到 SIM 并更新 MCC。
mncIMSI 移动设备网络代码 (MNC) 发生变更 — 检测到 SIM 并更新 MNC。
navigation导航类型(轨迹球/方向键)发生变更。(这种情况通常不会发生。)
orientation屏幕方向发生变更 — 用户旋转设备。
请注意:如果应用面向 Android 3.2(API 级别 13)或更高版本的系统,
则还应声明 "screenSize" 配置,因为当设备在横向与纵向之间切换时,
该配置也会发生变更。
screenLayout屏幕布局发生变更 — 不同的显示现可能处于活跃状态。
screenSize当前可用屏幕尺寸发生变更。该值表示当前可用尺寸相对于当前纵横比的变更,
当用户在横向与纵向之间切换时,它便会发生变更。此项为 API 级别 13 中的新增配置
smallestScreenSize物理屏幕尺寸发生变更。该值表示与方向无关的尺寸变更,
因此它只有在实际物理屏幕尺寸发生变更(如切换到外部显示器)时才会变化。
对此配置所作变更对应 smallestWidth 配置的变化。此项为 API 级别 13 中的新增配置
touchscreen触摸屏发生变更。(这种情况通常不会发生。)
uiMode界面模式发生变更 — 用户已将设备置于桌面或车载基座,或者夜间模式发生变更。
如需了解有关不同界面模式的更多信息,请参阅 UiModeManager
此项为 API 级别 8 中的新增配置



参考:

Handle configuration changes

App Manifest file - Activity

文章评论已关闭!