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


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.     }  

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM