Android: Activity在Restore时的数据缓存问题

阅读时间 约 1 分钟

红米Note上频繁NullPointException

继解决了Fragment中使用getActivity()返回null的问题后,在测试中又发现,在红米Note上离开程序后从后台返回时经常Crash,错误仍然是NullPointException。。。

项目需求是要求先登录,在LoginActivity登录完毕获取到Token后,我直接用Intent传给了主界面MainActivity再进行后续操作。但是当程序后台被杀掉后再恢复时,虽然会重新执行MainActivity的onCreate(),但是Intent内的数据却不会再有,我取出Token后没有做判断就使用,于是就抛出了NullPointException。

红米系列内存比较小,App切换到后台以后极易被干掉,所以这个问题在红米Note上比较容易重现。

保存数据

错误的原因在于没有缓存Intent传入的数据,那我们就缓存一下好了。

最简单的办法莫过于写入SharedPreference了,存入取出都很方便:

SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
// 存入数据
sp.edit().putString("token", token).apply();
// 取出数据
String token = sp.getString("token", null);

但是sp只适合存放少量的数据,若需要缓存的数据稍复杂一点用sp就会很麻烦,另一种办法是用数据库缓存,但数据库缓存代码量比较大,改动也不是很方便。

其实,Android已经考虑到了这种问题,提供了一种系统级的界面缓存数据的方法,即InstanceState机制。

利用Android的InstanceState机制

我们可以看到,在Activity的onCreate()方法是带参数的:

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
}

同时,Activity还带有两个方法:onSaveInstanceState()onRestoreInstanceState():

Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法。

它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState()会被调用。

但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。

通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。

因此,在InstanceState内保存数据的方法类似SP,非常简单:

@Override
public void onSaveInstanceState(Bundle savedInstanceState){
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString("token", token);
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState){
    super.onRestoreInstanceState(savedInstanceState);
    token = savedInstanceState.getString("token");
}

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	// 你也可以在onCreate()里恢复数据
	// 但这样做需要判断恢复的数据出来是否为null
	token = savedInstanceState.getString("token");
}

这样,在后台内存不足程序被回收时,会自动缓存数据,下次进入时自动恢复就不会抛出异常了。

参考

  1. Android开发之InstanceState详解