2013-02-21 3 views
3

나는 많은 이미지 (비트 맵)를 재생하고있는 하나의 데모 애플리케이션을 개발 중이다. 둘 이상의 활동에 동일한 이미지를 표시하기 위해 전역 비트 맵 객체를 사용하고 있습니다. 그러나 Bitmap.createBitmap (...)을 사용하여 비트 맵을 만들려고 할 때 OutOfMemoryError를 사용하고 있습니다. 나는 this code을 사용해 보았지만 여전히 같은 오류가 발생하고 있으며 내 응용 프로그램을 충돌시키고 OutOfMemoryError를 통해 충돌합니다.안드로이드의 비트 맵 OutOfMemoryError

나는 이것에 붙어있다. 누구든지 이것을 피할 수있는 해결책이 있습니까?

미리 감사드립니다.

비트 맵 크기를 디코딩하기 위해 아래 코드를 사용하도록 이미지 자르기 후 비트 맵을 가져오고 있습니다.

public static Bitmap loadFromBitmap(Context context, Bitmap b, int maxW, int maxH) throws IOException { 
     final BitmapFactory.Options options = new BitmapFactory.Options(); 
     Bitmap bitmap = null; 
     options.inScaled = false; 
     options.inPreferredConfig = Bitmap.Config.RGB_565; 
     options.inJustDecodeBounds = true; 
     BufferedInputStream stream = null; 
     ByteArrayOutputStream outstream = new ByteArrayOutputStream(); 
     b.compress(CompressFormat.JPEG, 100, outstream); 
     InputStream is = new java.io.ByteArrayInputStream(outstream.toByteArray()); 

     stream = new BufferedInputStream(is, 16384); 
     if (stream != null) { 
      options.inSampleSize = calculateInSampleSize(options, maxW, maxH); 
      stream = null; 
      stream = new BufferedInputStream(is, 16384); 
     } else { 
      return null; 
     } 
     options.inDither = false; 
     options.inJustDecodeBounds = false; 
     options.inPurgeable = true; 
     bitmap = BitmapFactory.decodeStream(stream, null, options); 
     if (bitmap != null) bitmap = BitmapUtils.resizeBitmap(bitmap, maxW, maxH); 
     return bitmap; 
    } 

    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
     // Raw height and width of image 
     final int height = options.outHeight; 
     final int width = options.outWidth; 
     int inSampleSize = 1; 

     if (height > reqHeight || width > reqWidth) { 

      // Calculate ratios of height and width to requested height and width 
      final int heightRatio = Math.round((float) height/(float) reqHeight); 
      final int widthRatio = Math.round((float) width/(float) reqWidth); 

      // Choose the smallest ratio as inSampleSize value, this will guarantee 
      // a final image with both dimensions larger than or equal to the 
      // requested height and width. 
      inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 
     } 

     return inSampleSize; 
    } 

오류 : 사실 options.inPurgeable = 및 op.inInputShareable = 사실 및 코드에서 방법을 절약 일부 메모리를 않습니다와

02-21 15:32:31.160: E/AndroidRuntime(2951): FATAL EXCEPTION: main 
02-21 15:32:31.160: E/AndroidRuntime(2951): java.lang.OutOfMemoryError 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:483) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:374) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:404) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.app.Activity.performCreate(Activity.java:4465) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1092) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1924) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1985) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.app.ActivityThread.access$600(ActivityThread.java:127) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1151) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.os.Handler.dispatchMessage(Handler.java:99) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.os.Looper.loop(Looper.java:137) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at android.app.ActivityThread.main(ActivityThread.java:4447) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at java.lang.reflect.Method.invokeNative(Native Method) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at java.lang.reflect.Method.invoke(Method.java:511) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
02-21 15:32:31.160: E/AndroidRuntime(2951):  at dalvik.system.NativeStart.main(Native Method) 
+0

이 [링크] (http://developer.android.com/training /displaying-bitmaps/load-bitmap.html#read-bitmap) 도움이 될 것입니다 –

+0

감사합니다 램,하지만 내 질문에 동일한 링크를 언급했다. : – anddev

+0

@anddev 결국 당신은 이미지를 늘릴 것인가? 어디에서 이미지를 얻고 있습니까? – Prateek

답변

4

디코딩하기 전에 outstream을 제거하십시오. 예를 들어 포인터를 null로 지정하십시오 (이 특정 스트림을 닫으면 스트림 유형으로 인해 아무 것도 작동하지 않습니다).

우리는 가능한 한 가벼워 야 할 정도로 꽤 광범위한 작업을하고 있습니다 ...

귀하의 코드는 close()를 사용하여 입력 스트림을 닫지 않아도 (여기에는 버그가 아니지만 decodeStream 이후에도 수행해야합니다).

Nostras ImageLoader을 사용해보십시오. 특정 크기의 컨테이너에 이미지를로드하는 것을 효율적으로 처리합니다. 즉, 이미지를 처리해야하기 전에 크기를 조정하고 압축합니다. 또한 한 번에 모두에게 도움이되는 콘텐츠 uris도 지원합니다.

2

편집 코드.

+0

메모리 절약 방법이란 무엇입니까? 나는 어떤 유형의 방법을 의미합니까? 어떤 사례라도 주시겠습니까? – anddev

+0

내 코드에서 이미 "options.inPurgeable = true"를 사용했습니다. 다른 곳에서는 필요하지 않습니까? – anddev

+0

또한 options.inInputShareable = true를 사용하십시오.이 두 가지 옵션 만 사용하십시오. – WSS

1

loadFromBitmap()을 호출하기 전에 System.gc()을 추가하십시오.

6

아 - 안드로이드에서 Google의 비트 맵 처리 구현과 함께 할 수있는 많은 멋진 전투.

메모리가있는 지붕을 때릴 때마다 필자는 약간의 메모리 프로파일 링을하는 경향이 있습니다. 항상 (항상 그런 것은 아니지만) 실수로 뭔가 잘못하고 있습니다 (예기치 않게 메모리 집약적 인). 코드를 탐색하기 만하면 비트 맵을 다시 사용하기 위해 세 스트림을 통해 코드를 적용해야 할 필요성에 조금 의아해합니다. 나는 내가이 정보를 이해할 수 있도록 약간의 정보를 놓친 것처럼 느낀다. 그러나 내가 너라면 그 단계들 각각에 얼마나 많은 메모리를 할당했는지 확실히 볼 것이다. (힙 덤프 -> hprof -conv -> 메모리 분석기는 당신의 친구입니다.)

그러나 나는 당신이 찾고있는 것이 BitmapRegionDecoder이라고 생각합니다. 사실은 최근에야 나 자신을 발견했으나 거의 정확하게 생각한 것 같습니다 - 전체 비트 맵을 메모리에로드하지 않고 비트 맵 (입력 스트림)에서 영역을 디코딩 할 수 있습니다 (너비/높이를 얻을 수도 있음) . 오직 단점은 안드로이드 2.3.3 +이지만, 요즘은 시장의 90 % 이상이 거대한 문제가 아니어야한다는 것입니다. 나는 이것을 사용하여 꽤 깔끔한 작업을 해왔다. (6000x4000 이미지의 부드러운 팬 및 줌) - 올바르게 사용하면 확실히 메모리 효과적이다.

[편집]

나는 최근에 오픈 소스 매우 큰 비트 맵의 ​​팬, 별거 및 핀치 줌을 처리 BitmapRegionDecoder를 사용하여 내 자신의 바보 구현입니다. 코드 (ASL2.0)는 https://github.com/micabyte/android_game

에서 찾을 수 있습니다.보고자하는 클래스는 BitmapSurfaceRenderer입니다. 지금까지 최대 8000x4000 이미지로 테스트했으며 매우 잘 작동하는 것 같습니다. 시간이되면, 어떻게 사용되는지를 보여주는 간단한 예제 애플리케이션을 작성하겠습니다.

+0

큰 비트 맵 처리의 예제 코드에 대한 링크가 추가되었습니다. –

+0

BitmapRegionDecoder의 경우 +1 – Entreco

+0

멋집니다. 간단한 예제 응용 프로그램을 설치할 시간을 찾았습니까? – Niels

1

null을 사용하기 전에 Bitmap.recycle() 메서드를 사용하십시오. 다음은

는 샘플입니다 :

public final void setBitmap(Bitmap bitmap) { 
    if (this.myBitmapImage != null) { 
     this.myBitmapImage.recycle(); 
    } 
    this.myBitmapImage = bitmap; 
} 

그리고 다음 다음과 같이 System.gc()를 호출하지 않고 myBitmapImage을 변경할 수 있습니다

setMyBitmap(anotherBitmap); 
    setMyBitmap(null); 
관련 문제