2011-04-14 7 views
2

죄송합니다. 반복되는 질문 인 것 같습니다.하지만 이미 게시 된 권장 사항 중 하나에 적합하지는 않습니다.OutOfMemoryError : 비트 맵 크기가 VM 예산을 초과합니다

내 응용 프로그램에 최대 20 개의 이미지 갤러리가 있습니다. 잠시 놀고 난 후에 앞뒤로 나는 OutOfMemoryError를 얻고있다.

이상한 점은 정적 참조를 갖고 있지 않으며 가능한 메모리 누수를 찾았으므로 지금까지 찾지 못했음을 확신 할 수 있습니다.

어쨌든 20 개의 이미지 (평균 100KB의 PNG)는 그리 좋아 보이지 않습니다. 그리고 뷰 캐시, 비트 맵용 SoftReference 홀더 등을 구현했습니다.

평균 20KB의 PNG 이미지로 내 응용 프로그램을 죽일 수 있습니까 ?? 진지하게? 이걸 어떻게 없앨 수 있니? 또한

http://blog.jteam.nl/2009/09/17/exploring-the-world-of-android-part-2/

이 위대한 게시하는 더 많은 아이디어를 따랐습니다?

public class AsyncImageLoader { 

    private final String TAG = getClass().getSimpleName(); 
    private Context mContext; 
    private HashMap<String, SoftReference<Bitmap>> mImageCache; 

    public AsyncImageLoader(Context context) { 
     mContext = context; 
      mImageCache = new HashMap<String, SoftReference<Bitmap>>(); 
    } 

    public Bitmap loadImage(final String identifier, final String imagePath, final ImageCallback imageCallback) { 

     if (mImageCache.containsKey(imagePath)) { 
      SoftReference<Bitmap> softReference = mImageCache.get(imagePath); 
      Bitmap bitmap = softReference.get(); 
      if (bitmap != null) { 
       Log.i(TAG, "Retrieving image from cache: " + imagePath); 
       return bitmap; 
      } 
     } 

     final Handler handler = new Handler() { 
      @Override 
      public void handleMessage(Message message) { 
       imageCallback.imageLoaded((Bitmap) message.obj, imagePath, identifier); 
      } 
     }; 

     new Thread() { 

      @Override 
      public void run() { 
       Bitmap bitmap = loadImageFromPath(imagePath); 
       mImageCache.put(imagePath, new SoftReference<Bitmap>(bitmap)); 
       Message message = handler.obtainMessage(0, bitmap); 
       handler.sendMessage(message); 
      } 

     }.start(); 

     return null; 
    } 

    public Bitmap loadImageFromPath(String path) { 

     if(!GeneralUtilities.isEmpty(path)) { 
      Log.i(TAG, "Loading image: " + path); 
      InputStream imageInputStream = null; 

      try {    
       final AssetManager assetManager = mContext.getResources().getAssets(); 
       imageInputStream = assetManager.open(path); 

       Bitmap bitmap = GeneralUtilities.decodeFile(imageInputStream); 

       imageInputStream.close(); 

       return bitmap; 
      } catch (final IOException e) { 
       Log.e(TAG, e.getMessage()); 
      }   
     } 

     return null; 
    } 

    public interface ImageCallback { 
     public void imageLoaded(Bitmap imageBitmap, String imagePath, String identifier); 
    } 
} 

및 GeneralUtilities.decodeFile 인 방법 :

final ImageView itemImage = cache.getHistoryImage();   
     //final ImageView itemFrame = cache.getFrame(); 

     String filename = item.getFilename().trim(); 

     itemImage.setTag("front_" + filename); 

     Bitmap cachedImage = mAsyncImageLoader.loadImage("front_" + filename, filename, new ImageCallback() { 

      public void imageLoaded(Bitmap imageBitmap, String imagePath, String identifier) { 

       ImageView imageViewByTag = (ImageView) mGallery.findViewWithTag(identifier); 
       if (imageViewByTag != null) { 
        imageViewByTag.setImageBitmap(imageBitmap); 
       } 
      } 
     }); 

     itemImage.setImageBitmap(cachedImage); 
: 나는 이런 식으로 뭔가를했습니다
public static Bitmap decodeFile(InputStream is){ 
     //Decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     BitmapFactory.decodeStream(is, null, o); 

     //The new size we want to scale to 
     final int REQUIRED_SIZE=140; 

     //Find the correct scale value. It should be the power of 2. 
     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; 
     } 

     //Decode with inSampleSize 
     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize = scale; 
     return BitmapFactory.decodeStream(is, null, o2); 
     } 

그리고 ArrayAdapter와의의 getView에서

은 ImageCache입니다
+0

내 갤러리에 코드를 표시하면 어떻게 이미지를 처리하나요? 내 갤러리에 60 개가 넘는 이미지 (100kb 이상)가있는 경우, 뭔가 잘못해야합니다 :) – WarrenFaith

+0

당신은 어떤 의미가 있습니까? 코드를 보내 주시겠습니까? 전체 활동은 여기에 넣으려면 꽤 큰입니다 – lblasa

+0

나는 단순히 내가 뭘 어떻게 할 ImageView에 비트 맵을 설정하는 어댑터에 질문을 업데이 트했습니다 – lblasa

답변

2

Android 프레임 워크에 버그가있는 것으로 보이지만 Google은이를 거부합니다.

문제점 8488을 읽었습니까?

http://code.google.com/p/android/issues/detail?id=8488

나는이 코드에 적용되는지 확실하지 않다 - 그러나 당신은 이미지 뷰에 이미지를 설정/업데이트하기 전에 권장 사항을 시도 할 수 있습니다.

기본적으로 Bitmap.recycle(), nulling 참조 (아마도 당신의 경우에는 관련이 없음) 및 System.gc() 호출을 명시 적으로 호출하는 것으로 귀결됩니다.

메모리가 비울 수 있지만 가비지 수집기가 비동기 적으로 실행되고 새 메모리가 실패 할 수 있습니다.

+0

전 정말 문제가 해결할 수있는 아니에요, 전적으로 무작위입니다. 때로는 UI를 사용하여 5 분을 플레이 한 후 때때로 활동을 시작하는 것이 중단됩니다. 언젠가 그것은 완벽하게 작동합니다. 나는 버그를 생각할 수 있지만,이 임의의 문제는 내가 무엇을 잘못 할 수 있는지 궁금해하고있다. 내 코드를 최적화하여 충돌 횟수를 줄 였지만 그 외에 무엇을 할 수 있는지 파악할 수 없습니다. – lblasa

관련 문제