加载大图片时,出现的OOM异常,以及处理OOM异常的方法

时间:2021-10-14 17:35:01

首先 , 得明白什么是 OOM异常, 即OutOfMemory异常,内存溢出导致的.
1,  如何计算出 加载图片进内存时的大小? 
在 Android中 , 加载一张图片时,比如 一张 2560X1920的高清图片,大小是  2560 x 1920 x 4 / 1024 / 1024  = 18.75 M,
android 中加载图片时,因为用的是argb处理, a 指透明度,r 指红色,g 指绿色, b 指蓝色,每个占8个bit即一个byte.所以,一个图片的像素是 4个字节.


2,为什么会出现 OOM异常?
上面已经计算出了图片加载进内存时的大小是 18.75 M,而我的这个模拟器上的虚拟机 的 堆内存 VM Heap只有 16M,所以就OOM了. 


3,处理OOM 异常的方法。
处理OOM异常的方法有很多,我这里只列出最简单的一种
先介绍下思路 : 
                              1,得到图片的宽和高
                               2,得到屏幕的宽和高(因为整个屏幕的像素都加载进内存,也不会造成内存溢出)
                               3,得到 图片的宽和屏幕宽(或控件宽)的比值,图片高和屏幕高(或控件高)的比值,选择比值大的那个
                                4,设置 Option的inSampleSize 属性来缩小图片
//这是一个按钮的点击事件,这样做的话,图片过大就会出现OOM异常
public void onClick(View view){
        //在这一步,将图片加载进内存时,就已经出OOM了
        Bitmap bitmap = BitmapFactory.decodeFile("/storage/sdcard/fury-006.jpg");
        imageView.setImageBitmap(bitmap);
}


//处理后的情况则是

    public void onClick(View v)
{
Options option = new Options();
/**如果该属性设为true的话,那么下面的decodeFile函数就会返回一个不带图片的bitmap对象,
* 并且,图片的实际宽高也会被映射到option对象中
*/
option.inJustDecodeBounds = true;
BitmapFactory.decodeFile("/storage/mnt/sdcard/fury-009.jpg", option);
//获得图片的实际宽高
int height = option.outHeight;
int width = option.outWidth;
//获得屏幕的宽高
WindowManager wm = this.getWindowManager();
int screen_height = wm.getDefaultDisplay().getHeight();
int screen_width = wm.getDefaultDisplay().getWidth();

//得到图片的宽高与屏幕或者ImageView控件大小的比值,选取合适的值
int scale = 1;
int sx = width/screen_width;
int sy = height/screen_height;
if(sx > sy && sx >= 1)
{
scale = sx;
}else if(sy > sx && sy >= 1)
{
scale = sy;
}
//如果该值设为false,那么就会返回带图片的Bitmap对象
option.inJustDecodeBounds = false;
option.inSampleSize = scale;//该值大于1的话,就会把图片按比例缩小,得到一个bitmap对象
Bitmap bitmap = BitmapFactory.decodeFile("/storage/sdcard/fury-009.jpg", option);

imageView.setImageBitmap(bitmap);
}

}