前言
Android应用有一个常常被忽略的问题,但问题出现时你又不得不面对。比如
-
Activity横竖屏转换时Fragment重影
-
应用长时间处于后台,并用户重新切到前台时,Activity显示异样或者需要等待一段时间才能显示内容
这类问题都与Activity的恢复重建机制相关,如果你想知道怎么解决这类问题,以及Activity恢复重建机制内部原理。这篇文或许能够帮到你。
1 什么时候会重建
并不是任何Activity的销毁行为都会触发Activity数据的保存。只有销毁行为是被系统发起的并且今后有可能恢复的时候才会触发。
1.1 不会触发重建机制
- 按返回按键。比如,A Actvivity启动B Activity,BActivity中返回不会调用BActivity的OnSaveInstanceState()方法
- 最近使用屏幕中滑动关闭 Activity。
- 从设置中【停止】应用
- 完成某种“完成”操作,开发者通过调用Activity #finish()方法完成
1.2 有可能会触发重建机制的
触发恢复重建机制就是两大类
- 系统回收内存时kill掉。
- 横竖屏切换和语言切换等配置发生变化时kill重建。(可以通过 Activity #isChangingConfigurations()方法判断是否为配置更改发生的)。
当由系统发起而非人为手动关闭Activity的时候,Activity有可能在未来的某个时机恢复重建。Android系统提供了两套机制,用以保存和恢复界面状态。 这两套机制我个人分别给其取名为 Save-Restore InstanceState机制和RetainNonConfiguration机制
2 Save-Restore InstanceState机制
- Save-Restore InstanceState机制的初衷是保存界面的一些瞬时状态,比如ListView滑动的位置、ViewPager的position一些TextView的文本内容。保证用户进入新建Activity的时候能尽快的看到界面状态的恢复。
- Save-Restore InstanceState是一些比较轻量级的数据,因为保存过程需要经历数据的序列化和反序列化。
对于开发者时机操作层面来说,Save-Restore InstanceState机制的核心就是Activity中 onSaveInstanceState() 、onCreate()和onRestoreInstanceState()这三个回调方法。
2.1 onSaveInstanceState()
#Activity
protected void onSaveInstanceState(@NonNull Bundle outState) {
//A、整个view树中的view相关信息有机会保存到整个bundle中
outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
Parcelable p = mFragments.saveAllState();
if (p != null) {
outState.putParcelable(FRAGMENTS_TAG, p);
}
if (mAutoFillResetNeeded) {
outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
getAutofillManager().onSaveInstanceState(outState);
}
dispatchActivitySaveInstanceState(outState);
}
- onSaveInstanceState(outState)的被调用的条件:非手动杀死Activity而是系统kill同时可能会在未来重建时。
- 在Activity被系统kill时会调用onSaveInstanceState(outState)方法,允许开发者把一些今后重建时需要的一些状态数据存储到o