1.现象
在使用安卓手机的一些应用调用照相机时,我们会发现有时候当我们拍照完毕时,程序会出现闪退,非常影响用户体验。目前项目中也有类似的拍照上传功能,当使用米3手机测试时,拍照上传功能可以正常使用,当我们换上红米或者其他一些比较早或者比较低端的手机时,就出现了闪退的问题。
1.1开启相机的intent
/* mPictureCachePath为当前照相相片的存储路径 */
pictureCachePath = Utility.getExternalCacheDir(this)+...;
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(mPictureCachePath)));
startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
1.2onActivityResult接收intent返回值并获取bitmap
File file = new File(mPictureCachePath);
if (file.exists()) {
Bitmap bitmap = BitmapUtils.convertToBitmap(
mPictureCachePath, width, height);
}
2.分析问题
经过debug我们可以发现,如果程序发生闪退,此时mPictureCachePath值为null,可是我们在一开始已经为这个变量赋值,为什么当从相机程序返时,mPictureCachePath这个全局变量会变为null?
那我们给mPictureCachePath赋个初始值看看,结果当程序返回时,这个变量的值不是我们赋值过的路径,而是那个初始值。这样,我推测当前所在的Activity在相机程序返回时应该是被重新创建了。
通过调试,我们发现如果使用米3手机,程序不闪退,相机程序在返回我们的Actvity时没有执行onCreate方法,而使用红米手机,程序闪退时,此时我们的Actvity执行了onCreate,也就是说用红米时,当我们开启相机程序时,我们自己的Activity已经被销毁了! 所以当相机程序返回我们的Activity时,这个Activity是刚刚创建的,我们刚刚为图片创建的路径记录变量此时其实并没有被赋值。
3.解决方式
既然变量有可能丢,那么我们就可以把这个变量记录下来,可以使用sp等。假如我们的程序中还需要记录一些其他的变量,比如一些我们自定义的比较复杂的类,sp就没办法满足存储的需要。
此时我们可以使用如下两个方法
protected void onSaveInstanceState(Bundle outState)
protected void onRestoreInstanceState(Bundle savedInstanceState)
这两个方法并不是Activity每次都会调用的,我们注意到onCreate和onRestoreInstanceState都有个Bundle类型的参数,那么这个参数是谁传来的呢?肯定是onSaveInstanceState传来的。
当我们的Activity在未经我们自己finish的情况下被结束(没有被回收也会执行onSaveInstanceState),onSaveInstanceState方法就会被调用。此时我们就可以利用outState参数来存储我们的数据,当onCreate或者onRestoreInstanceState(只有Activity被真正回收后才调用)时,将这些数据拿出来重新赋值给我们的成员变量,这样,就算是Activity被销毁了,我们依然可以重新获得相关变量的值。
/**
* 保存相册参数
* 说明:对于配置低的手机,开启照相机时,当前activity会被回收,导致再次返回该activity时,原先保存
* 的变量被重新初始化,导致程序无法运行,造成崩溃。此处需要记录相关变量信息,如果activity异常退出,
* 再次进入时调用onRestoreInstanceState函数就可以恢复这些变量的值。
*/
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.i(TAG, "onSaveInstanceState");
/* 保存相片路径 */
outState.putString("mCurrentSelectPictureCachePath", mCurrentSelectPictureCachePath);
}
/**
* 恢复相册参数
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.i(TAG, "onRestoreInstanceState");
/* 恢复当前相片存储路径 */
mPictureCachePath = savedInstanceState.getString("mCurrentSelectPictureCachePath", mCurrentSelectPictureCachePath);
......
}
这样,mPictureCachePath的值就可以被保存下来,当程序返回时,如果Activity没有被回收,则不会执行onRestoreInstanceState方法,如果被回收了,就调用onRestoreInstanceState方法对变量值进行恢复。