2012-10-22 6 views
0

나는 안드로이드에서 초보자입니다! 거대한 비트 맵 (> 1200 * 1000)을 사용하는 앱을 개발할 때 Android SDK의 큰 문제가 있습니다. 앱에서 문제가 발생합니다. 동일한 크기 (3-5 개)의 여러 레이어/비트 맵이 필요합니다.). 문제는 이러한 할당 중 하나에서 메모리 힙이 매우 빠르게 소비되고 OutOfMemory 예외가 트리거된다는 것입니다.안드로이드 비트 맵 재사용

좋은 점은 내가 같은 시간에 모든 비트 맵을 필요로하지 않는다는 것입니다.

recycle() 메서드 호출을 시도했지만 비트 맵의 ​​메모리가 원시 메모리가 아닌 힙에 있으므로 폐기 된 것으로 알고 있습니다. 또한 특정 비트 맵에서 모든 참조를 제거하고 심지어는 수동으로 System.gc()를 호출하려고 시도했지만 비트 맵을 제거 할 수 없습니다. 좋아, 아마도 내가 알지 못하는 메모리 누수가 있을지 모르지만 나는 의심 스럽다.

나는 모든 종류의 솔루션을 시도했지만 그 중 아무 것도 작동하지 않았습니다.

나에게 가장 좋은 방법은 비트 맵을 다시 사용하는 것이지만 BitmapFactory의 디코딩 방법은 메모리를 사용하는 새로운 비트 맵을 할당하는 것만 알고 있습니다.

내 질문은, 안드로이드에서 작동 할 수있는 비트 맵 픽셀을 재사용하는 방법을 알고 있습니까? (다른 비트 맵/픽셀 배열을 할당하지 않고 비트 맵의 ​​픽셀을 덮어 씀) ??? 문제는 내가 GarbageCollector 솔루션에 상주 할 수 없다는 것입니다. 왜냐하면 그 비트 맵이 메모리에서 제거되었는지/다른 비트 맵이 할당되지 않을 것임을 확신해야 할 때 앱에 특정 순간이 있기 때문입니다.

또 다른 해결책은 다음과 같습니다. 힙 메모리를 통과하지 않고 sdcard에 직접 비트 맵을 그리는 방법을 알고 있습니까? 순간에 큰 비트 맵 (원래 크기의 두 배)을 할당하여 두 개의 다른 처리 된 비트 맵을 연결하려고 시도 할 때 충돌이 발생합니다 ... 그래서 제가 묻는 것입니다. 캔버스의 다른 드로잉 객체를 데이터 스트림에서 직접 인스턴스화 할 수 있습니까?

다른 솔루션은 힙 메모리를 시뮬레이트하는 가상 스왑 메모리와 같은 것을 사용하지만 SDCARD 또는 기타 캐싱을 사용하는 것입니다. 그러나 이것을하는 방법을 찾을 수 없습니다.

+0

"비트 맵의 ​​메모리가 원시 메모리가 아닌 힙에 있으므로 폐기 된 것으로 알고 있지만 recycle() 메서드 호출을 시도했습니다." 이것은 안드로이드 3.2 이후 사실 일종입니다 – Blackbelt

+0

예! 안드로이드 4.0에서 내 목표! – user602445

답변

2

사용자 정의 비트 맵 작업을 수행하기위한 별도의 클래스를 작성 :

활동에서 그런
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 


class BitmapLoader 
{ 
public static int getScale(int originalWidth,int originalHeight, 
    final int requiredWidth,final int requiredHeight) 
{ 
    //a scale of 1 means the original dimensions 
    //of the image are maintained 
    int scale=1; 

    //calculate scale only if the height or width of 
    //the image exceeds the required value. 
    if((originalWidth>requiredWidth) || (originalHeight>requiredHeight)) 
    { 
     //calculate scale with respect to 
     //the smaller dimension 
     if(originalWidth<originalHeight) 
      scale=Math.round((float)originalWidth/requiredWidth); 
     else 
      scale=Math.round((float)originalHeight/requiredHeight); 

    } 

    return scale; 
} 

public static BitmapFactory.Options getOptions(String filePath, 
     int requiredWidth,int requiredHeight) 
{ 

    BitmapFactory.Options options=new BitmapFactory.Options(); 
    //setting inJustDecodeBounds to true 
    //ensures that we are able to measure 
    //the dimensions of the image,without 
    //actually allocating it memory 
    options.inJustDecodeBounds=true; 

    //decode the file for measurement 
    BitmapFactory.decodeFile(filePath,options); 

    //obtain the inSampleSize for loading a 
    //scaled down version of the image. 
    //options.outWidth and options.outHeight 
    //are the measured dimensions of the 
    //original image 
    options.inSampleSize=getScale(options.outWidth, 
      options.outHeight, requiredWidth, requiredHeight); 

    //set inJustDecodeBounds to false again 
    //so that we can now actually allocate the 
    //bitmap some memory 
    options.inJustDecodeBounds=false; 

    return options; 

} 



public static Bitmap loadBitmap(String filePath, 
     int requiredWidth,int requiredHeight){ 


    BitmapFactory.Options options= getOptions(filePath, 
      requiredWidth, requiredHeight); 

    return BitmapFactory.decodeFile(filePath,options); 
} 
} 

의 requiredWidth 및 requiredHeight을 SD 카드에서 얻은 비트 맵의 ​​filepath를 제공하고 설정이 클래스의 Bitmap reqBitmap = loadBitmap(String filePath,int requiredWidth,int requiredHeight) 메소드를 호출 비트 맵의 ​​배율을 조정할 치수를 지정합니다. 이제 reqBitmap을 사용하십시오.

이렇게하면 큰 비트 맵은 힙 메모리에로드되기 전에 축소됩니다. 나는 똑같은 문제를 겪었고 이것으로 나를 해결했다. :)

+0

당신, vickey하지만, 이미이 일을했지만 충분하지 않습니다 ... 여전히 OutOfMemory 예외가 발생합니다. 나에게 픽셀 버퍼 또는 뭔가를 재사용 할 수있는 가능성을주는 뭔가가 필요하다. – user602445

+1

나를 위해 이것이 멋지게 작동합니다! – erdomester

1

recycle()이 나를 위해 작동하지 않는 등의 비슷한 문제가있었습니다. 그래서 저는 myBitmap = null처럼 사소한 것을했습니다. 이는 가비지 콜렉터에게 myBitmap이 참조 해제되었고 더 이상 필요하지 않다는 것을 나타냅니다. 따라서 힙을 비우는 일을 할 것입니다. 그런 다음 메모리 예외없이 새로운 비트 맵을로드하기 위해 myBitmap을 사용할 수 있습니다.

관련 문제