Activity 数据的保存和恢复
当 Activity 的 onSaveInstanceState()
方法被调用时,Activity 会自动收集 View Hierachy
(视图层次)中每一个 View 的状态。请注意,只有内部实现了 View 类状态保存和恢复方法的控件才能被收集状态数据。一旦onRestoreInstanceState()
方法被调用,Activity 将这些收集的数据回传给 View Hierachy
中的 View,而这种回传时数据与 View 一一对应关系的依据就是 View 提供之前保存数据时的相同 id,通常在布局中通过 android:id
属性定义的。
虽然这些 View 的状态可以被自动保存,但是 Activity 成员变量却不行。他们将随着 Activity 一起被销毁。你不得不通过 onSaveInstanceState()
和onRestoreInstanceState()
方法手动保存和恢复这些成员变量。
...
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("data", date);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
date = savedInstanceState.getString("data");
}
Fragment 数据的保存和恢复
Fragment 类里面没有 onRestoreInstanceState()
方法,一旦 Fragment 从回退栈(BackStack)中返回时,View 将会被销毁和重建。这种情况属于,Fragment 没有被销毁,Fragment 实例仍然在那儿,包括实例里的成员变量。所以你不需要对成员变量做任何事情。不需要额外添加任何代码。因此,没有发生 Instance 状态保存。
而 Fragment 的 View 被销毁,每一个内部实现 View 类保存和恢复方法的 View,例如 EditText 或者 TextView,只要设置了android:freezeText="true",都将被自动保存和恢复状态。
所以 Fragment 状态保存和恢复的条件是,Fragment 中每一个 View 内部都必须实现状态保存和恢复方法。
Android 提供了一个通过 onSaveInstanceState()
和 onRestoreInstanceState()
方法用于 View 内部保存和恢复状态的机制。开发人员在自定义 View 时实现这两个方法即可。
区分 Fragment 状态和 View 状态
为了使你的代码变得更加清晰和易于维护,你必须将 Fragment 状态和 View 状态区分开来。对于任何属于 View 的属性,在 View 内部实现状态保存和恢复。而对于那些属于 Fragment 的属性,就在 Fragment 内部实现即可。
...
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
date = savedInstanceState.getString("data");
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("data", date);
}
Fragment 重叠问题
问题描述:
一种比较多的出现方式是,应用长时间处于后台,但由于设备内存吃紧,导致 Activity 被销毁,而当用户再次打开应用时便会发生 Fragment 重叠的问题。还有就是程序出错后应用重新启动界面的时候等
问题分析:
出现上面问题的根源就是 Activity 销毁重建的时候,之前的 Fragment 自动保存了 View 状态,而 Fragment 的实例已经被销毁,当再次创建的时候就会显示 UI 重叠的问题。
解决方法:
方法一:在 Activity 提供的 onAttachFragment() 方法中处理
@Override
public void onAttachFragment(android.support.v4.app.Fragment fragment) {
super.onAttachFragment(fragment);
if (fragment instanceof MyFragment) {
myFragment = (MyFragment) fragment;
}
}
方法二:在创建 Fragment 前添加判断,判断是否已经存在
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("MyFragment");
if (myFragment == null) {
myFragment = MyFragment.newInstance();
fragmentTransaction.add(R.id.content, myFragment, "MyFragment");
} else {
myFragment = fragment;
}
方法三:直接利用 savedInstanceState 判断即可
if (savedInstanceState == null) {
myFragment = MyFragment.newInstance();
fragmentTransaction.add(R.id.content, myFragment, "MyFragment");
} else {
myFragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("MyFragment");
}
参考文章
译Android Activity 和 Fragment 状态保存与恢复的最佳实践
Android Fragment 的使用,一些你不可不知的注意事项