XiYO

现实不同情弱者,命运不相信眼泪。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

java.lang.OutOfMemoryError: bitmap size exceeds VM budget解决方法

Posted on 2012-05-26 10:23  XiYO  阅读(6234)  评论(0编辑  收藏  举报
1
BitmapFactory.decodeFile(imageFile);

用BitmapFactory解码一张图片时,有时会遇到该错误。这往往是由于图片过大造成的。要想正常使用,则需要分配更少的内存空间来存储。

BitmapFactory.Options.inSampleSize

设置恰当的inSampleSize可以使BitmapFactory分配更少的空间以消除该错误。inSampleSize的具体含义请参考SDK文档。例如:

1
2
3
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

如何设置恰当的inSampleSize

设置恰当的inSampleSize是解决该问题的关键之一。BitmapFactory.Options提供了另一个成员inJustDecodeBounds。

1
2
3
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。

查看Android源码,Android提供了一种动态计算的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public static int computeSampleSize(BitmapFactory.Options options,
        int minSideLength, int maxNumOfPixels) {
    int initialSize = computeInitialSampleSize(options, minSideLength,
            maxNumOfPixels);
 
    int roundedSize;
    if (initialSize <= 8) {
        roundedSize = 1;
        while (roundedSize < initialSize) {
            roundedSize <<= 1;
        }
    } else {
        roundedSize = (initialSize + 7) / 8 * 8;
    }
 
    return roundedSize;
}
 
private static int computeInitialSampleSize(BitmapFactory.Options options,
        int minSideLength, int maxNumOfPixels) {
    double w = options.outWidth;
    double h = options.outHeight;
 
    int lowerBound = (maxNumOfPixels == -1) ? 1 :
            (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
    int upperBound = (minSideLength == -1) ? 128 :
            (int) Math.min(Math.floor(w / minSideLength),
            Math.floor(h / minSideLength));
 
    if (upperBound < lowerBound) {
        // return the larger one when there is no overlapping zone.
        return lowerBound;
    }
 
    if ((maxNumOfPixels == -1) &&
            (minSideLength == -1)) {
        return 1;
    } else if (minSideLength == -1) {
        return lowerBound;
    } else {
        return upperBound;
    }
}  

使用该算法,就可动态计算出图片的inSampleSize。

1
2
3
4
5
6
7
8
9
10
11
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageFile, opts);
             
opts.inSampleSize = computeSampleSize(opts, -1, 128*128);      
opts.inJustDecodeBounds = false;
try {
    Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);
    imageView.setImageBitmap(bmp);
    } catch (OutOfMemoryError err) {
    }

另外,可以通过Bitmap.recycle()方法来释放位图所占的空间,当然前提是位图没有被使用。

 

获取缩略图关键代码

 

 

byte[] imageByte=getImageFromURL(urlPath[i].trim());

 

 //以下是把图片转化为缩略图再加载

 BitmapFactory.Options options = new BitmapFactory.Options(); 

 options.inJustDecodeBounds = true;      //首先设置.inJustDecodeBounds为true

 Bitmap bitmap=BitmapFactory.decodeByteArray(imageByte, 0, imageByte.length, options);    //这时获取到的bitmap是null的,尚未调用系统内存资源

 options.inJustDecodeBounds = false;        得到图片有宽和高的options对象后,设置.inJustDecodeBounds为false。

 int be = (int)(options.outHeight / (float)200); 

         if (be <= 0)   be = 1; 

         options.inSampleSize = be;          //计算得到图片缩小倍数

 bitmaps[i]=BitmapFactory.decodeByteArray(imageByte, 0, imageByte.length,options);                          //获取真正的图片对象(缩略图)

 /**  

* 根据图片网络地址获取图片的byte[]类型数据

* @param urlPath 图片网络地址

 * @return 图片数据

  */  

  1.     public byte[] getImageFromURL(String urlPath){  
  2.         byte[] data=null;  
  3.         InputStream is=null;  
  4.         HttpURLConnection conn=null;  
  5.         try {  
  6.             URL url=new URL(urlPath);  
  7.             conn=(HttpURLConnection) url.openConnection();  
  8.             conn.setDoInput(true);  
  9.             //conn.setDoOutput(true);  
  10.             conn.setRequestMethod("GET" );  
  11.             conn.setConnectTimeout(6000 );  
  12.             is=conn.getInputStream();  
  13.             if(conn.getResponseCode()==200 ){  
  14.                 data=readInputStream(is);  
  15.             }  
  16.             else  System.out.println("发生异常!" );  
  17.               
  18.         } catch (MalformedURLException e) {  
  19.             e.printStackTrace();  
  20.         } catch (IOException e) {  
  21.             e.printStackTrace();  
  22.         }  
  23.         finally{  
  24.             conn.disconnect();  
  25.             try {  
  26.                 is.close();  
  27.             } catch (IOException e) {  
  28.                 e.printStackTrace();  
  29.             }  
  30.         }  
  31.         return data;  
  32.     }  
  33.       
  34.     /**  
  35.      * 读取InputStream数据,转为byte[]数据类型  
  36.      * @param is  InputStream数据  
  37.      * @return  返回byte[]数据  
  38.      */  
  39.     public byte[] readInputStream(InputStream is) {  
  40.         ByteArrayOutputStream baos=new ByteArrayOutputStream();  
  41.         byte[] buffer=new byte[1024 ];  
  42.         int length=-1 ;  
  43.         try {  
  44.             while((length=is.read(buffer))!=-1 ){  
  45.                 baos.write(buffer, 0 , length);  
  46.             }  
  47.             baos.flush();  
  48.         } catch (IOException e) {  
  49.             e.printStackTrace();  
  50.         }  
  51.         byte[] data=baos.toByteArray();  
  52.         try {  
  53.             is.close();  
  54.             baos.close();  
  55.         } catch (IOException e) {  
  56.             e.printStackTrace();  
  57.         }  
  58.         return data;  
  59.     }  
  60.       
  61.     /**  
  62.      * 根据网络图片地址集批量获取网络图片  
  63.      * @param urlPath  网络图片地址数组  
  64.      * @return    返回Bitmap数据类型的数组  
  65.      */  
  66.     public Bitmap[] getBitmapArray(String[] urlPath){  
  67.         int length=urlPath.length;  
  68.         if(urlPath==null||length<1 ){  
  69.             return null;  
  70.         }  
  71.         else{  
  72.             Bitmap[] bitmaps=new Bitmap[length];  
  73.             for (int i = 0 ; i < length; i++) {  
  74.                 byte[] imageByte=getImageFromURL(urlPath[i].trim());  
  75.                   
  76.                 //以下是把图片转化为缩略图再加载  
  77.                 BitmapFactory.Options options = new BitmapFactory.Options();   
  78.                 options.inJustDecodeBounds = true;  
  79.                 Bitmap bitmap=BitmapFactory.decodeByteArray(imageByte, 0 , imageByte.length, options);  
  80.                 options.inJustDecodeBounds = false;  
  81.                 int be = (int)(options.outHeight / (float)200 );   
  82.                 if (be <= 0 )   be =  1 ;   
  83.                 options.inSampleSize = be;   
  84.                 bitmaps[i]=BitmapFactory.decodeByteArray(imageByte, 0 , imageByte.length,options);  
  85.             }  
  86.             return bitmaps;  
  87.         }  
  88.           
  89.     }