在很多的Android项目中都会出现加载网络图片或是加载本地SD卡中的图片导致应用出现OOM异常,应用挂死的现象。查了很多资料,终于对应用的OOM做出了一定程度的优化。故写出来大家都分享一下。
OOM(Out Of Memory )异常 ,顾名思义这个异常是说你的内存不够用或者耗尽了,在Android中,一个Process 只能使用16M内存,如果超过了这个限制就会跳出这个异常。这样就要求我们要时刻想着释放资源System.gc();值得注意的是Bitmap在不用时,一定要recycle,不然OOM是非常容易出现的。
查了很多资料,有说是强制增大应用的内存空间,有说是使用软引用及弱引用试得虚拟机更好更快的实现内存回收机制,全都用了,可OOM异常依然存在。这是为什么呢?
最后查看API源码才发现:
当使用 imageView.setBackgroundResource,imageView.setImageResource, 或者BitmapFactory.decodeResource 、BitmapFactory.decodeFile 这样的方法来设置一张大图片的时候,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法解流的方式,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。
另外,需要特别注意: decodeStream是直接读取图片资料的字节码了, 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
1.得到资源文件中的图片bitmap
/**
* 得到资源文件中的图片bitmap
* @param context
* @param resId
* @return Bitmap
*/
public static Bitmap readBitMap(Context context, int resId){
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
InputStream is = context.getResources().openRawResource(resId);
Bitmap bm = BitmapFactory.decodeStream(is,null,opt);
return bm;
}
2. 通过DecodeFile解析SD卡中的图片
/**
* 通过DecodeFile解析SD卡中的图片
* @param file
* @return Bitmap
*/
public static Bitmap getBitmapByDecodeFile(File file){
Bitmap newBit = null;
try {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
Bitmap bitmap= BitmapFactory.decodeStream(bis);
newBit = Bitmap.createScaledBitmap(bitmap, 180, 180, false);
bis.close();
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
return newBit;
}
3.在设置imageView的background的时候没有setImageBitmap(bitmap)方法,但是有img.setBackgroundDrawable(bitmapDrawale)方法
故我们还需要通过得到的bitmap在去获取他的bitmapDrawable
BitmapDrawable bmdrawable = new BitmapDrawable(context.getResources(), bitmap);
至此,应用中出现的OOM异常就基本解决。