应用在运行的过程中如果设备的配置发生变化(如屏幕方向、键盘可用性及语言),Android系统会重启正在运行的Activity以利用与新的设备配置相匹配的备用资源来加载应用。重启过程中(先后调用Activity的onDestroy()和onCreate()方法),先前Activity当中未被保存的数据资源会丢失。为了避免数据因Activity的重启而丢失,可以通过以下两种方式来对数据进行保存:
1. 调用onSaveInstanceState()方法。
onSaveInstanceState(Bundle outState)方法有一个Bundle类型的参数。在onSaveInstanceState()方法中,我们通过调用Bundle对象的putXXX()方法,将Activity中数据和变量的值保存在Bundle对象当中。之后Activity重启时会再次调用onCreate(Bundle savedInstanceState)方法,该方法中也有一个Bundle类型的参数,调用该Bundle对象的getXXX()方法即可得到通过onSaveInstanceState()方法保存的数据。此方法主要适用于需要保存的数据较少并且较简单的情形。若重启Activity时需要恢复大量的数据,或者需要重新建立网络连接和执行其它一些密集的操作,使用Bundle来保存和恢复数据可能会给用户留下应用运行缓慢的体验。在这种情况下,则可通过下面这种方式来减轻重新初始化Activity的负担。
2. 通过保留Fragment来对数据进行保存。
要在应用的配置变更时将有状态的对象保留在片段中,需要进行以下操作:
1. 创建一个Fragment的子类并声明对有状态对象的引用;
2. 在创建的片段中调用setRetainInstance(boolean);
3. 将片段添加到Activity;
4. 重启Activity后,使用FragmentManager得到片段并获取保存的对象。
例如,按以下方式定义片段:
public class RetainedFragment extends Fragment{
private MyDataObject data;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
注意:切勿传递与Activity绑定的对象,例如:Drawable、Adapter、View或其他任何与Context关联的对象。否则,它将泄漏原始Activity实例的所有视图和资源。(泄漏资源意味着应用将继续持有这些资源,但是无法对其进行垃圾回收,因此可能会丢失大量内存)。
然后,使用FragmentManager将定义的片段添加到Activity,并将需要保存状态的对象传入Fragment。当配置变更重新启动Activity时,我们可以获取片段中的数据对象。Activity的代码如下所示:
public class MyActivity extends Activity{
private RetainedFragment dataFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
if (dataFragment == null) {
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, “data”).commit();
dataFragment.setData(loadMyData());
}
...
}
@Override
public void onDestroy() {
super.onDestroy();
dataFragment.setData(collectMyLoadedData());
}
}
以上代码中,onCreate()方法第一次执行时会添加一个Fragment对象,之后Activity重启引用该片段获取其保存的对象。