Android java.lang.OutOfMemoryError: bitmap 解决方法

BitmapFactory.Options.inSampleSize

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

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

如何设置恰当的inSampleSize

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

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提供了一种动态计算的方法。网络

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。app

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()方法来释放位图所占的空间,固然前提是位图没有被使用。ide

获取缩略图关键代码:url

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 图片数据
 */  
   public byte[] getImageFromURL(String urlPath){  
       byte[] data=null;  
       InputStream is=null;  
       HttpURLConnection conn=null;  
       try {  
           URL url=new URL(urlPath);  
           conn=(HttpURLConnection) url.openConnection();  
           conn.setDoInput(true);  
           //conn.setDoOutput(true);  
           conn.setRequestMethod("GET" );  
           conn.setConnectTimeout(6000 );  
           is=conn.getInputStream();  
           if(conn.getResponseCode()==200 ){  
               data=readInputStream(is);  
           }  
           else  System.out.println("发生异常!" );  
             
       } catch (MalformedURLException e) {  
           e.printStackTrace();  
       } catch (IOException e) {  
           e.printStackTrace();  
       }  
       finally{  
           conn.disconnect();  
           try {  
               is.close();  
           } catch (IOException e) {  
               e.printStackTrace();  
           }  
       }  
       return data;  
   }

 

/**  
    * 读取InputStream数据,转为byte[]数据类型  
    * @param is  InputStream数据  
    * @return  返回byte[]数据  
    */  
   public byte[] readInputStream(InputStream is) {  
       ByteArrayOutputStream baos=new ByteArrayOutputStream();  
       byte[] buffer=new byte[1024 ];  
       int length=-1 ;  
       try {  
           while((length=is.read(buffer))!=-1 ){  
               baos.write(buffer, 0 , length);  
           }  
           baos.flush();  
       } catch (IOException e) {  
           e.printStackTrace();  
       }  
       byte[] data=baos.toByteArray();  
       try {  
           is.close();  
           baos.close();  
       } catch (IOException e) {  
           e.printStackTrace();  
       }  
       return data;  
   }  
     
   /**  
    * 根据网络图片地址集批量获取网络图片  
    * @param urlPath  网络图片地址数组  
    * @return    返回Bitmap数据类型的数组  
    */  
   public Bitmap[] getBitmapArray(String[] urlPath){  
       int length=urlPath.length;  
       if(urlPath==null||length<1 ){  
           return null;  
       }  
       else{  
           Bitmap[] bitmaps=new Bitmap[length];  
           for (int i = 0 ; i < length; i++) {  
               byte[] imageByte=getImageFromURL(urlPath[i].trim());  
                 
               //如下是把图片转化为缩略图再加载  
               BitmapFactory.Options options = new BitmapFactory.Options();   
               options.inJustDecodeBounds = true;  
               Bitmap bitmap=BitmapFactory.decodeByteArray(imageByte, 0 , imageByte.length, options);  
               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);  
           }  
           return bitmaps;  
       } 
   }