关于res目录下图片引起的OOM解决方法

时间:2021-08-13 12:27:18

参考链接:http://blog.csdn.net/coderinchina/article/details/40964205

参考链接:http://blog.csdn.net/shineflowers/article/details/41648745


最近的项目中需要用到比较多的图片,而且图片的像素和内存都占用得比较多。导致一两张图下来直接OOM了。

对于这个难缠的问题,这两天参考了很多博文。


那么先了解下因为图片过大而产生的OOM

现在的机器分配为每个进程分配的内存大约为32M,但是当手机内存不足够分配出32M的时候~抑或是当本app的运行内存大于32M的时候都会引起OOM。

所以我们先把注意力放在图片上面先。


Android中计算一张图片所占内存大小方法:图片长*宽*所占像素字节数,而像素字节数Android中也就四种,

1:ALPHA_8 占1个字节

2:ARGB_4444 占2个字节

3:ARGB_8888 占4个字节

4:RGB_565  占2个字节

:ARGB指的是一种色彩模式,里面A代表Alpha,R表示redG表示greenB表示blue,其实所有的可见色都是红绿蓝组成的,所以红绿蓝又称为三原色。 A  R  G  B
透明度 红色 绿色 蓝色

而这些字节数是可以通过bitmap对象去设置的bitmap.setConfig(Bitmap.Config.ARGB_4444);

如果这是个定值,那么要改变一个张图片的大小,就只能改宽或者高了,如果只改高,宽不变的话,就会造成图片变形,因此一般都是一起改动,所以图片要缩放,而缩放时根据屏幕的宽和高来缩放的,因为Android设备很多,每个屏幕的宽和高也不一样,这样就能达到加载大图片避免OOM。

例如最近项目中用到的一图片1280*720像素的图片,而且使用的是ARGB_8888,那么算出来占用的内存:1280*720*4/1024/1024=3.5M一张图片

所以几张这样的图就能把Android的内存搞爆了。

看上面公式也知道图片加载到内存中是看图片的像素和质量来决定它在运行内存中的大小

然后总结了最好的一个解决方案:

压缩压缩还是压缩图片(但是具体有两种压缩方法)



第一种方式:压缩图片的比例(代码参考于各大网站)

我们可以通过设置BitmapFactory.Optiions的inJustDecodeBounds属性为true,这样的话不会加载图片到内存中,

但是会将图片的width和height属性读取出来,我们可以利用这个属性来对bitmap进行压缩。Options.inSampleSize 可以设置压缩比。




public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {    
// 源图片的高度和宽度
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// 计算出实际宽高和目标宽高的比率
final int heightRatio = Math.round((float) height / (float) reqHeight);
final int widthRatio = Math.round((float) width / (float) reqWidth);
//计算缩放比例
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,int reqWidth, int reqHeight) {
// 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// 调用上面定义的方法计算inSampleSize值
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// 使用获取到的inSampleSize值再次解析图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}


第二种方式:压缩图片的质量

从刚刚提及的公式上面知道,我们可以通过bitmap.setConfig(Bitmap.Config.ARGB_4444)去设置具体Bitmap的显示质量。以下方法参考这个方法

<pre name="code" class="java" style="color: rgb(51, 51, 51); font-size: 12.5px; letter-spacing: 0.5px; line-height: 22.5px;"> public 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);
        return BitmapFactory.decodeStream(is, null, opt);
    }

 
其中resId可以直接传入Drawable文件目录下的文件(不用把图片放置与raw目录下) 


以下是这几天遇到OOM的解决办法,实测第二个方法效果颇好。