2011-04-14 66 views
2

對不起,它似乎是一個重複的問題,但我認爲我不符合任何已發佈的建議。OutOfMemoryError:位圖大小超過VM預算

我的應用程序中有最多20張圖像的圖庫。玩了一段時間後,我得到OutOfMemoryError。

奇怪的是,我不抱任何靜態引用,我已經搜索了可能的內存泄漏問題,我可以保證,我還沒有發現一個至今。

無論如何,20幅圖像(100KB平均的PNG)並不像那麼多。我已經實現了一個視圖緩存,SoftReference的持有者爲位圖等

它是100KB的平均20個PNG圖像足以殺死我的應用程序?當真?我怎麼能擺脫這個?我跟着這個偉大的職位也

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

任何更多的想法?

這是ImageCache:

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是:

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我已經是這樣的:

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); 
+0

向我們展示您的畫廊的代碼,你如何處理圖像那裏...因爲我在我的畫廊(比100KB大)超過60張圖片,你必須做一些錯誤:) – WarrenFaith 2011-04-14 15:30:41

+0

你有什麼平均值向你發送代碼?整個活動是相當大的放在這裏 – lblasa 2011-04-14 15:36:27

+0

我已經更新了問題,在適配器中,我只是將位圖設置爲ImageView – lblasa 2011-04-14 15:42:04

回答

2

雖然Google似乎否認它,但Android框架似乎存在一個錯誤。

您是否已閱讀問題8488?

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

我不知道這是否適用於你的代碼 - 但你可能設置/更新的圖像上的ImageView之前嘗試的建議。

基本上,它歸結爲調用Bitmap.recycle(),調零引用(可能你的情況irrellevant)和顯式調用調用System.gc()。

垃圾收集器似乎異步運行和新的可能會失敗,即使內存可以被釋放。

+0

我不能解決問題,完全是隨機的。有時它會在開始活動時崩潰,有時會在用戶界面上玩5分鐘後崩潰。有時甚至可以很好地工作。我可以想到一個錯誤,但這個隨機問題讓我想知道我做錯了什麼。我優化了我的代碼,減少了崩潰的次數,但我無法弄清楚我還能做什麼 – lblasa 2011-04-18 10:39:34

相關問題