红米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");
}
这样,在后台内存不足程序被回收时,会自动缓存数据,下次进入时自动恢复就不会抛出异常了。
参考