2012-02-27 4 views
0

저는 Android에서 매우 새롭고 Bitmap 및 BitmapFactory를 사용하여 그리드보기에 SDcard 이미지를 넣으려고합니다. 그러나 같은 오류의 원인 :OutOfMemoryError에서 비트 맵 크기가 초과되었습니다. 비트 맵 크기가 VM 예산을 초과합니다.

ERROR/AndroidRuntime(6137):  java.lang.OutOfMemoryError: bitmap size exceeds VM budget  
ERROR/AndroidRuntime(6137):  at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 
ERROR/AndroidRuntime(6137):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459) 
ERROR/AndroidRuntime(6137):  at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:271) 
+1

이미 답변이 너무 많습니다. http://stackoverflow.com/search?q=bitmap+size+exceeds+VM+budget. –

+0

[OutOfMemoryError : 비트 맵 크기가 VM 예산을 초과합니다 : - Android] 가능한 중복 (http://stackoverflow.com/questions/2928002/outofmemoryerror-bitmap-size-exceeds-vm-budget-android) –

답변

1

먼저 응용 프로그램에 전체 품질 이미지를 복사하지 마십시오. 품질/크기를 조금 아래로 샘플링하는 Options 클래스를 사용하면 썸네일 비트 맵을 작성하는 경우 inSampleSize = 8을 사용

ContentResolver cr = getContentResolver(); 
InputStream is = cr.openInputStream(chosenImageUri); 
Options optionSample = new BitmapFactory.Options(); 
optionSample.inSampleSize = 4; // Or 8 for smaller image 
Bitmap bitmap = BitmapFactory.decodeStream(is, null, optionSample); 
// Bitmap bitmap = BitmapFactory.decodeFile(filePathString, optionSample); 

보십시오.

여러 비트 맵 개체를 만들고 각각이 동일한 이미지를 약간 변경하면 bitmap.recycle()을 사용해보십시오. 그러나 recycle()은 앱에 이전 비트 맵에 대한 참조가있는 경우 (감지하기 어려울 수 있음) 런타임 오류가 발생할 수 있으므로 사용시주의하십시오.

도움이되는지 알려주세요.

0

Android는 메모리에 더 관심이 많으며 BitmapFactory는 제한된 크기의 이미지 만 허용합니다.

다음은 사용하기 전에 이미지 크기를 조정하는 데 도움이 될 것입니다.

import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Matrix; 

public class ImageScale 
{ 

/** 
* Decodes the path of the image to Bitmap Image. 
* @param imagePath : path of the image. 
* @return Bitmap image. 
*/ 

public Bitmap decodeImage(String imagePath) 
{ 
    Bitmap bitmap=null; 

    try 
    { 

     File file=new File(imagePath); 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 

     BitmapFactory.decodeStream(new FileInputStream(file),null,o); 
     final int REQUIRED_SIZE=200; 
     int width_tmp=o.outWidth, height_tmp=o.outHeight; 

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

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

     options.inSampleSize=scale; 
     bitmap=BitmapFactory.decodeStream(new FileInputStream(file), null, options); 

    } 
    catch(Exception e) 
    { 
     bitmap = null; 
    }  
    return bitmap; 
} 

/** 
    * Resizes the given Bitmap to Given size. 
    * @param bm : Bitmap to resize. 
    * @param newHeight : Height to resize. 
    * @param newWidth : Width to resize. 
    * @return Resized Bitmap. 
    */ 
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) 
{ 

    Bitmap resizedBitmap = null; 
    try 
    { 
     if(bm!=null) 
     { 
      int width = bm.getWidth(); 
      int height = bm.getHeight(); 
      float scaleWidth = ((float) newWidth)/width; 
      float scaleHeight = ((float) newHeight)/height; 
      // create a matrix for the manipulation 
      Matrix matrix = new Matrix(); 
      // resize the bit map 
      matrix.postScale(scaleWidth, scaleHeight); 
      // recreate the new Bitmap 
      resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true); 

     } 
    } 
    catch(Exception e) 
    { 
     resizedBitmap = null; 
    } 

    return resizedBitmap; 
} 

} 

는 URI에서 이미지 경로가이 기능을 사용 얻으려면 :

private String decodePath(Uri data) 
{   
    Cursor cursor = getContentResolver().query(data, null, null, null, null); 
    cursor.moveToFirst(); 
    int idx = cursor.getColumnIndex(ImageColumns.DATA); 
    String fileSrc = cursor.getString(idx); 
    return fileSrc; 

} 
5

잘 확인을, 분명히이 문제는 SO에 100 시간을 대답 얻을 것이다. 여기에 아이디어 :

  • 우선 장치의 안드로이드 버전에 따라 :

    당신이 안드로이드 버전 2.x 이하 (허니 콤 이전의 모든 버전) 당신이 취한 메모리를 사용하는 경우 비트 맵 인스턴스는 Runtime.getRuntime(). xxxMemory() 메소드에 의해보고 된대로 힙에있는 여유 메모리의 양에 반영되지 않습니다. 이러한 인스턴스는 힙 외부의 메모리에 배치됩니다. Bitmap 인스턴스가 사용할 메모리 양을 추적하려면 수동으로 imageWidth * imageHeight * 4로 계산해야합니다. 이것은 (힙 (off heap)) 메모리에서 이미지가 차지하는 바이트를 줄 것이다. 이 메모리 사용량과 힙 메모리 사용량은 Android가 특정 장치의 응용 프로그램에 할당 한 최대 메모리보다 작은 총계를 가져야합니다. 그렇지 않으면 OutOfMemory 오류가 발생합니다.

  • Android에 의해 프로세스에 할당 된 총 메모리는 장치 및 Android 버전에 크게 의존합니다. 이것은 16에서 48 메가 사이에있을 수 있습니다. 이전 기기의 경우 16 또는 32입니다. 최신 기기의 경우 32 또는 48입니다.이 경우 타겟팅 할 각 기기를 개별적으로 확인해야합니다. 또한 런타임에이 작업을 수행하여 메모리에 저장할 수있는 물건의 양에 대한 가이드로 사용할 수 있습니다 (어쩌면 이미지를 메모리에 16Mb의 메모리를 할당하는 장치에로드하기 전에 이미지를 다운 샘플링하려는 경우 일 수도 있음)

  • Android Honeycomb (버전 3.xx) 이상에서는 Bitmap 인스턴스가 힙 메모리를 사용합니다. 이렇게하면 이미지를로드 한 후에도 여유 메모리가 얼마나 남아 있는지 쉽게 추적 할 수 있습니다. 또한 이러한 Android 버전에서 Bitmap 인스턴스는 가능한 경우 가비지 수집됩니다. 사전 벌집에서 당신은 다량 전화해야합니다

    비트 맵.재활용();

비트 맵 인스턴스가 사용하는 메모리를 확보하십시오.

  • 가 통과 된 수 옵션 등 만 화상의 폭과 높이를 얻을 복호화 전에 다운 샘플링하도록하기 위해 이미지를 디코딩 (비트 맵 인스턴스를 생성) 할 BitmapFactory를 사용. 이렇게하면 실제로 이미지를 메모리에 저장하기 전에 이미지의 메모리 사용량을 파악할 수 있습니다. 문서 확인 : http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html

  • 모든 장치에서 작동하지는 않지만 모험을 느낄 수 있습니다. OpenglSurfaceView를 만들고 쿼드에 텍스처로 이미지를 표시하십시오. 단순함을 위해 직각 투영법을 사용할 수 있습니다 (2d의 모양 만 제공해야하는 경우). 여기에있는 속임수는 이미지를 메모리에 비트 맵으로로드하고 OpenGL 텍스처와 비트 맵 인스턴스를 지우는 것입니다. 실제 이미지는 여전히 텍스처 개체에서 표시 할 수 있으며 이러한 개체는 프로세스 별 메모리 제한에 의해 제한되지 않습니다.

관련 문제