2013-05-27 43 views
0

我的應用程序將有超過350個圖像將從數據庫解碼。我從圖像數據創建位圖並根據設備屏幕分辨率對其進行縮放。當我試圖將所有這些位圖保存到內存中時,我正面臨OutOfMemory異常。然後,BitmapFactory.Options.inPurgeable在各個地方被推薦用作避免OutOfMemoryExceptions的一種方式。Android位圖OutOfMemory問題

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inPurgeable = true; 
options.inInputShareable = true; 

Bitmap bitmap = BitmapFactory.decodeByteArray(imagaeData, 0, size, options); 
... 
.. 
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, true); 

我將此縮放位圖緩存到HashMap並將其用於圖像視圖。同樣,我在將位圖加載到內存時面臨OutOfMemory異常。我不瞭解inPurgeable是否適合我的情況。我想知道縮放的位圖是否會引用字節數組。當我使用縮放位圖時,它是否具有decodeByteArray中使用的inPurgeable選項的效果。我無法弄清楚如何處理這個位圖內存問題。感謝你的幫助。

+1

在BitmapFactory.Options您可以指定一個縮放比例 – njzk2

+0

我想根據自己定義的比例因子向上或向下放大或縮小。例如,如果我創建的位圖大小是50 X 50,縮放因子是2.0,我想將位圖放大到100 X 100的大小。可以使用BitmapFactory.Options來完成嗎? – Keerthi

+0

不完全。選項包含一個下采樣參數。通常,您將在大小模式下打開位圖以僅獲取大小,然後測量比例因子以獲取降採樣圖像,然後使用此模式以默認模式重新打開圖像,然後在createScaledBitmap中使用此圖像。 – njzk2

回答

0

350張照片相當多。你確定你一次都需要他們嗎?

另外:當你創建一個縮放的位圖,你有他們在內存中的兩次 - > 700內存中的圖像是太方式太多。您應該檢查在選項上使用inScale以便再次將其減小到350,並減少內存佔用量。

我仍然認爲,即使在優化的方式350圖像太多。你應該考慮一個懶惰的加載解決方案。

+0

您能否告訴我如何使用inScaled選項將位圖從50 X 50縮放到75 X 75.我不知道這個選項。如果您可以提供任何示例代碼,請感謝您的幫助。 – Keerthi

0

您可以試試BitmapFactory.Options.inScaled & BitmapFactory.Options。 inScreenDensity來獲取縮放位圖。

而你需要一個更好的方式來緩存位圖在內存中。您最好在位圖的HashMap中保存位圖的WeakReference,並且您可以切換到LinkedHashMap以實現簡單的LRU緩存實現。

你並不真的需要緩存所有的圖像,因爲他們永遠不會有機會在一個屏幕上顯示。

0

哇,嘗試在內存中一次保存350個位圖聽起來很瘋狂。即使他們很小,我也不會推薦它。當然,你將無法一次顯示所有這些位圖,那麼在同一時間將所有這些位圖保存在內存中又有什麼意義呢?

你真的應該考慮使用類似Square's Picasso lib的東西來處理圖像加載和縮放。畢加索處理「適配器中的ImageView回收和下載取消」,「自動內存和磁盤緩存」以及最後「最小內存使用情況下的複雜圖像轉換」。

+0

我真的不想在內存中放置全部350個位圖。最初我在做Disck Cache。後來我開始瞭解inPurgeable選項來處理內存不足的問題。由於我正在使用磁盤緩存,所以在獲取位圖並將其加載到圖像視圖時存在延遲。有性能問題。但是當我在RAM中放置所有圖像時,將位圖加載到圖像視圖沒有延遲。這是我期望將所有位圖保存到內存中以減少將位圖加載到imageview中的延遲的原因。 – Keerthi

+1

我認爲當你滾動瀏覽長列表/網格圖像時,廣泛接受的延遲加載圖像就足夠了,不是嗎?想想默認相機庫加載圖像的方式。它運行良好,不存在遇到任何問題的風險。只要您使用async app,Picasso或類似的解決方案加載,應用程序仍然會感覺靈敏和快速。 – britzl

+0

謝謝britzl。這說得通。我想確保是否有任何最佳方法在內存中有效地保存位圖。 – Keerthi

0

使用此方法,首先(文件指向SD卡上的照片)縮小圖像尺寸

//decodes image and scales it to reduce memory consumption 
private Bitmap decodeFile(File f){ 
    try { 
     //decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     FileInputStream stream1=new FileInputStream(f); 
     BitmapFactory.decodeStream(stream1,null,o); 
     stream1.close(); 

     //Find the correct scale value. It should be the power of 2. 
     // maximum size is 50 
     final int REQUIRED_SIZE=40; 
     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; 
     FileInputStream stream2=new FileInputStream(f); 
     Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2); 
     stream2.close(); 
     return bitmap; 
    } catch (FileNotFoundException e) { 
    } 
    catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

//下面是如何調用上面的方法

    String path = "/mnt/sdcard/DCIM/camera/IMG_2001.jpg"; 
        Drawable background = hash_map.get(path); 
        if (background == null) { 
        try { 
         Bitmap bitmap = decodeFile(new File(path)); 
         background = new BitmapDrawable(bitmap); 
         if (hash_map.size() > 600) { 
          // to prevent HashMap from growing too large. 
          hash_map.clear(); 
         } 
         hash_map.put(path, background); 
        } catch (Throwable e) { 
         // in case there is an exception, like running out of memory. 
         if (e instanceof OutOfMemoryError) { 
          hash_map.clear(); 
         } 
        } 
       }