Android-应用程序在选择非常大的图像时会因内存不足而崩溃



在下面的代码中,当在代码中第二次处理decodeFile时,函数"getScaledBitmap"中的大尺寸图像出现异常"字节分配内存不足"。这个下面的函数被调用了4次,因为我正在屏幕上处理4个不同的图像。

请对此提供指导。

private Bitmap processimage(String picturePath){
    Bitmap thumbnail =null;
    thumbnail=getScaledBitmap(picturePath,500,500);
    Matrix matrix = null;
     try {
            ExifInterface exif = new ExifInterface(picturePath);
            int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); 
            int rotationInDegrees = bal.exifToDegrees(rotation);
            matrix = new Matrix();
            if (rotation != 0f) {
                matrix.preRotate(rotationInDegrees);
                thumbnail=Bitmap.createBitmap(thumbnail, 0,0, thumbnail.getWidth(), thumbnail.getHeight(), matrix, true);   
            }

        } catch (IOException e) {
            e.printStackTrace();
        }catch (Exception e) {
         e.printStackTrace();
        }
     return thumbnail;
}
protected Bitmap getScaledBitmap(String picturePath, int width, int height) {
    Bitmap result=null;
    try{
        BitmapFactory.Options sizeOptions = new BitmapFactory.Options();
        sizeOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(picturePath, sizeOptions);
        int inSampleSize = calculateInSampleSize(sizeOptions, width, height);
        sizeOptions.inJustDecodeBounds = false;
        sizeOptions.inSampleSize = inSampleSize;
        result=BitmapFactory.decodeFile(picturePath, sizeOptions);
    }catch(Exception ex){
        ex.printStackTrace();
    }
    return result;
}
protected int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    if (height > reqHeight || width > reqWidth) {
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;
        while ((halfHeight / inSampleSize) > reqHeight
                || (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}
public  int exifToDegrees(int exifOrientation) {        
        if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; } 
        else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {  return 180; } 
        else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {  return 270; }            
        return 0;    
     }
to scale image and to catch oom error  I use the following code(but for one image).I am not sure if it will be ok for you..and include try catch for OOM in your code to avoid crash
Options options = new BitmapFactory.Options();
      try{
          options.inScaled = false;
          options.inDither = false;
          options.inPreferredConfig = Bitmap.Config.ARGB_8888;
       imgBitmap=decodeFile(file);  
                  }
       catch(OutOfMemoryError e){ 
           System.out.println("out of memory");
           flag=1;
               System.out.println("clearing bitmap????????????");
               if (imgBitmap!=null) { 
               this.setBackgroundResource(0);
               this.clearAnimation();
           imgBitmap.recycle(); 
            imgBitmap = null;}

    //     }
       }  

优化图像文件的方法

 public Bitmap decodeFile(File f) {
                try {
                    // decode image size
                    BitmapFactory.Options o = new BitmapFactory.Options();
                    o.inJustDecodeBounds = true;
                    o.inDither=false;                     //Disable Dithering mode
                    o.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
                    o.inInputShareable=true; 
                    o.inPreferredConfig = Bitmap.Config.ARGB_8888;
                    //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
                    o.inTempStorage=new byte[16*1024]; 
                    BitmapFactory.decodeStream(new FileInputStream(f), null, o); 
                    // Find the correct scale value. It should be the power of 2.
                     int REQUIRED_SIZE = 300;
                    int width_tmp = o.outWidth, height_tmp = o.outHeight; 
                    if(REQUIRED_SIZE  > width_tmp)
                    REQUIRED_SIZE  = width_tmp;
                    int scale = 1;
                    while (true) {
                        if (width_tmp / 2 < REQUIRED_SIZE
                                || height_tmp / 2 < REQUIRED_SIZE) 
                            break; 
                        width_tmp /= 2;
                        height_tmp /= 2;
                        scale *= 2;
                        System.out.println(scale+"______________________________-");  
                    }
                    // decode with inSampleSize
                    BitmapFactory.Options o2 = new BitmapFactory.Options();
                    o2.inDither=false;
                    o2.inScaled = false;
                    o2.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
                    o2.inInputShareable=true; 
                    //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
                    o2.inTempStorage=new byte[24*1024]; 
                    o2.inSampleSize = 2; 
                    o2.outWidth = width_tmp;
                    o2.outHeight = height_tmp;
                    o2.inPreferredConfig = Bitmap.Config.ARGB_8888;
                    try {
                        BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(o2,true);    
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                        } catch (SecurityException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {  
                            e.printStackTrace();
                        } catch (NoSuchFieldException e) {
                            e.printStackTrace();
                        }

                    o2.inJustDecodeBounds = false;
                    return BitmapFactory.decodeStream(new FileInputStream(f), null,  
                            o2);
                } 
                catch (FileNotFoundException e) {
                    System.out.println("file not found");
                }
                return null;
            }

在许多手机上,一个应用程序有足够的RAM用于恰好一个图像,加载第二个图像总是会导致内存不足的异常。即使你可以在手机的RAM中加载2张照片,另一部手机也会有更好的摄像头,而且会出现故障。如果你想在屏幕上显示大图像,你必须缩放它们。如果你想合并两个大图像,那么,你就有问题了。我建议在一个单独的过程中(命令行工具或服务)执行此操作。请注意,应用程序可以在清单中请求大堆:android:largeHeap=["true" | "false"](链接)。但最有可能的是,您可以避免在RAM中加载两个图像。

最新更新