某些设备配置可能会在运行时发生变化。发生这种变化时,Android 会重启正在运行的Activity
(先后调用onDestroy()
和onCreate()
)。重启行为旨在通过利用与新设备配置相匹配的备用资源来自动重新加载应用,从而帮助它适应新配置。
如要妥善处理重启行为,Activity 必须恢复其先前的状态。然而,可能会遇到这种情况:重启 Activity 需要恢复大量数据、重新建立网络连接或执行其他密集操作,不仅成本高昂,而且会给用户留下应用运行缓慢的体验。在此情况下,还有两个选择:
在配置变更期间保留对象
- 允许 Activity 在配置变更时重启,但是需将有状态对象传递给 Activity 的新实例。
- 使用系统通过
onSaveInstanceState()
回调保存的Bundle
,但可能无法完全恢复 Activity 状态,因为该类并非用于携带大型对象(例如位图),并且其中的数据必须依次在主线程中进行序列化和反序列化,而这可能会消耗大量内存并降低配置变更的速度。 - 在此情况下,可通过使用
ViewModel
对象来减轻重新初始化 Activity 的负担。系统会在配置变更时保留 ViewModel,使其成为保存界面数据的理想场所,无需再次查询这些数据。
自行处理配置变更
如果无法使用首选项(onSaveInstanceState()、ViewModel 和持久存储)来保留界面状态,或者应用在特定配置变更期间无需更新资源,并且因性能限制需要尽量避免 Activity 重启,则可声明 Activity 自行处理配置变更,从而阻止系统重启 Activity。
注意:自行处理配置变更可能会提高使用备用资源的难度,因为系统不会自动应用这些资源。只有在必须避免 Activity 因配置变更而重启的无奈情况下,才可考虑使用此方法,并且不建议对大多数应用使用此方法。
如要声明由 Activity 处理配置变更,在清单文件中编辑相应的<activity>
元素,以包含android:configChanges
属性,该属性的值表示要处理的配置。
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name">
MyActivity
会接收到对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();
}
}
如果无需根据这些配置变更更新应用,则可不必实现onConfigurationChanged()
。在此情况下,应用仍会使用配置变更前所用的全部资源,但是,应用应始终能在保持先前状态完好的情况下关闭和重启,因此不应该认为,使用此方法即可无需保留正常 Activity 生命周期中的状态。