Android 載入大圖片時報OOM的解決方案(原始碼)

yangxi_001發表於2013-11-26
在Android中:


  1.一個程式的記憶體可以由2個部門組成:java 施用記憶體 ,C 施用記憶體 ,這兩個記憶體的和必需小於16M,不然就會出現各人熟悉的OOM,這個就是熬頭種OOM的情況。


  2.一朝記憶體分配給Java後,以後這塊記憶體縱然開釋後,也只能給Java的施用,這個估計跟java虛擬機器裡把記憶體分成好幾塊進行快取的原因有關,反正C就別想用到這塊的記憶體了,所以要是Java突然佔用了一個大塊記憶體,縱然很快開釋了:


  C能施用的記憶體 = 16M - Java某一瞬間佔在校大學生創業點子用的最大記憶體。


  而Bitmap的生成是路程經過過程malloc進行記憶體分配的,佔用的是C的記憶體。


Code :


  
/**  
 * 載入大圖片工具類:解決android載入大圖片時報OOM異常  
 * 解決原理:先設定縮放選項,再讀取縮放的圖片資料到記憶體,規避了記憶體引起的OOM  
 * @author: 張進   
  
 * @time:2011/7/28  
 */   
public class BitmapUtil {   
   
    public static final int UNCONSTRAINED = -1;   
       
    /*  
  * 獲得設定資訊  
  */   
 public static Options getOptions(String path){   
  Options options = new Options();   
  options.inJustDecodeBounds = true;//只描邊,不讀取資料    
  BitmapFactory.decodeFile(path, options);   
  return options;   
 }   
    
    
 /**  
  * 獲得影象  
  * @param path  
  * @param options  
  * @return  
  * @throws FileNotFoundException  
  */   
 public static Bitmap getBitmapByPath(String path, Options options , int screenWidth , int screenHeight)throws FileNotFoundException{   
  File file = new File(path);   
  if(!file.exists()){   
   throw new FileNotFoundException();   
  }   
  FileInputStream in = null;   
  in = new FileInputStream(file);   
  if(options != null){   
   Rect r = getScreenRegion(screenWidth,screenHeight);   
   int w = r.width();   
   int h = r.height();   
   int maxSize = w > h ? w : h;   
   int inSimpleSize = computeSampleSize(options, maxSize, w * h);   
   options.inSampleSize = inSimpleSize; //設定縮放比例    
   options.inJustDecodeBounds = false;   
  }   
  Bitmap b = BitmapFactory.decodeStream(in, null, options);   
  try {   
   in.close();   
  } catch (IOException e) {   
   e.printStackTrace();   
  }   
  return b;   
 }   
    
    
       
 private static Rect getScreenRegion(int width , int height) {   
  return new Rect(0,0,width,height);   
 }   
   
   
 /**  
  * 獲取需要進行縮放的比例,即options.inSampleSize  
  * @param options  
  * @param minSideLength  
  * @param maxNumOfPixels  
  * @return  
  */   
 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 == UNCONSTRAINED) ? 1 :   
                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));   
        int upperBound = (minSideLength == UNCONSTRAINED) ? 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 == UNCONSTRAINED) &&   
                (minSideLength == UNCONSTRAINED)) {   
            return 1;   
        } else if (minSideLength == UNCONSTRAINED) {   
            return lowerBound;   
        } else {   
            return upperBound;   
        }   
    }   
       
    
}  
 

工具類的使用:
  
String path = "/sdcard/test2.jpg";   
    try {   
  Bitmap bitmap = BitmapUtil.getBitmapByPath(path, BitmapUtil.getOptions(path), screenWidth, screenHeight);   
 } catch (FileNotFoundException e) {   
  e.printStackTrace();   
 }  
 



相關文章