2010-02-08 123 views
29

我有一堆圖片網址。我必須下載這些圖像並將它們逐個顯示在我的應用程序中。我使用SoftReferences以及Sdcard將圖像保存在收藏集中,以避免重新提交併改善用戶體驗。處理大型位圖

問題是我不知道有關位圖大小的任何信息。事實證明,當我使用BitmapFactory.decodeStream(InputStream)方法時,我偶爾會發生OutOfMemoryException異常。所以,我選擇使用BitmapFactory選項(sample size = 2)對圖像進行縮減採樣。這給出了更好的輸出:沒有OOM,但是這會影響較小圖像的質量。

我應該如何處理這種情況?有沒有辦法選擇性地僅對高分辨率圖像進行降採樣?

+0

官方[Android培訓](http://developer.android.com/training/index.html)網站現在有一個名爲[高效顯示位圖]的類(http://developer.android.com/training/顯示位圖/ index.html)和一個教訓,[有效載入大型位圖](http://developer.android.com/training/displaying-bitmaps/load-bitmap.html)。 [Caching Bitmaps](http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html)課程還介紹了使用硬引用內存緩存而不是WeakReference或SoftReference進行緩存的一些信息。 – AdamK 2012-04-10 09:58:59

回答

55

有一個在BitmapFactory.Options類名爲inJustDecodeBounds一個選項(一個我忽略),javadoc的案文如下:

如果設置爲true,解碼器將 返回NULL(無位),但 出...字段仍將被設置, 允許調用者查詢 位圖,而不必爲其像素分配 內存。

我用它找出了位圖的實際大小,然後選擇使用inSampleSize選項向下採樣。這至少可以在解碼文件時避免任何OOM錯誤。

參考:
1. Handling larger Bitmaps
2. How do I get Bitmap info before I decode

+9

+1當你找到答案時回答你自己的問題;想想那些谷歌和找到你的問題,但沒有答案。 – Will 2010-02-09 13:19:12

+0

它真的很好,如果我想要的尺寸,但我得到OOM錯誤,當我想解碼文件到位圖並將該位圖設置爲ImageView。請告訴我如何優化或以其他任何方式解決此問題。 – 2012-11-27 07:37:32

12

我所做自己是:

  • 使用inJustDecodeBounds來獲得圖像的原始尺寸
  • 有一個固定的用於加載位圖的最大表面(例如1M像素)
  • 檢查圖像表面是否低於極限,如果是的話,直接加載它
  • 如果不是計算理想的寬度和高度,你應該加載位圖以保持低於最大麴面(這裏有一些簡單的數學運算)。這爲您提供了一個浮點率,您可以在加載位圖
  • 時想要應用此比例,以便將此比率轉換爲合適的inSampleSize(不降低圖像質量的2的冪)。我用這個功能:
 
int k = Integer.highestOneBit((int)Math.floor(ratio)); 
if(k==0) return 1; 
else return k; 
  • 則由於位圖將被裝載比最大表面略微更高的分辨率(因爲你不得不使用2的功率較小),你就會有調整位圖的大小,但速度會更快。
+0

感謝您添加例程來計算樣本大小。它用一條重要信息增加了線索。 – Samuh 2010-09-15 07:52:55

11

經過幾天努力,以避免我與不同的設備讓所有內存溢出錯誤,我創建了這一點:

private Bitmap getDownsampledBitmap(Context ctx, Uri uri, int targetWidth, int targetHeight) { 
    Bitmap bitmap = null; 
    try { 
     BitmapFactory.Options outDimens = getBitmapDimensions(uri); 

     int sampleSize = calculateSampleSize(outDimens.outWidth, outDimens.outHeight, targetWidth, targetHeight); 

     bitmap = downsampleBitmap(uri, sampleSize); 

    } catch (Exception e) { 
     //handle the exception(s) 
    } 

    return bitmap; 
} 

private BitmapFactory.Options getBitmapDimensions(Uri uri) throws FileNotFoundException, IOException { 
    BitmapFactory.Options outDimens = new BitmapFactory.Options(); 
    outDimens.inJustDecodeBounds = true; // the decoder will return null (no bitmap) 

    InputStream is= getContentResolver().openInputStream(uri); 
    // if Options requested only the size will be returned 
    BitmapFactory.decodeStream(is, null, outDimens); 
    is.close(); 

    return outDimens; 
} 

private int calculateSampleSize(int width, int height, int targetWidth, int targetHeight) { 
    int inSampleSize = 1; 

    if (height > targetHeight || width > targetWidth) { 

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

     // 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; 
} 

private Bitmap downsampleBitmap(Uri uri, int sampleSize) throws FileNotFoundException, IOException { 
    Bitmap resizedBitmap; 
    BitmapFactory.Options outBitmap = new BitmapFactory.Options(); 
    outBitmap.inJustDecodeBounds = false; // the decoder will return a bitmap 
    outBitmap.inSampleSize = sampleSize; 

    InputStream is = getContentResolver().openInputStream(uri); 
    resizedBitmap = BitmapFactory.decodeStream(is, null, outBitmap); 
    is.close(); 

    return resizedBitmap; 
} 

此方法適用於我測試的所有設備,但我覺得質量還可以使用我不知道的其他進程會更好。

我希望我的代碼可以幫助其他開發人員在相同的情況下。我也非常感謝高級開發人員能夠提供幫助,並提出有關其他流程的建議,以避免流程中丟失(少)質量。

+1

好東西。但是calculateSampleSize是錯誤的。我現在更新了這個帖子來修復它。 – Zammbi 2014-04-10 22:00:28

+1

一件非常不錯的作品。感謝你的分享! – MacD 2014-08-11 20:12:19