Android解決大圖片內存溢出

在Android平臺上內存溢出是一件很頭疼的事情,但解決辦法仍是有的,今天來翻譯一篇谷歌官方提供的解決方案,原文能夠參見:http://developer.android.com/training/displaying-bitmaps/load-bitmap.htmlhtml

 更有效地加載大的圖片

圖片有不一樣的形狀可大小,在不少狀況下他們老是大於一個典型應用UI的要求。例如,系統提供的Gallery程序顯示了手機相機拍攝的圖片,這些圖片的分辨率老是大於設備屏幕的分辨率。java

考慮到跟有限的設備內存打交道,理想狀況下,你只須要加載在內存中的較低分辨率版本。分辨率較低的UI組鍵須要與顯示它的大小相匹配。具備更高的分辨率的圖像並不會帶來顯而易見的好處,可是仍然佔用了寶貴的內存和由於縮放帶來了額外的性能開銷。android

這節課將要經過載入一個較小的二次取樣的小圖片帶你來編碼一個大的圖片而不須要超過每一個程序最大的內存。緩存

 讀取圖片的尺寸和類型

BitmapFactory類提供了一些列建立不一樣圖片種類的編碼方式,例如:decodeByteArray()decodeFile()decodeResource() 等等。基於你的圖片數據來源選擇一個最合適的編碼方式。這些編碼方法試圖爲建立Bitmap分配內存,所以能夠很容易地致使OutOfMemory異常。每一個類型的解碼方法有額外的簽名,讓您指定經過BitmapFactory.Options類的解碼選項。經過設置BitmapFactory.Options的inJustDecodeBounds屬性設置爲true,能夠解碼避免內存分配,返回的Bitmap爲空,但返回outWidth,outHeight和outMimeType。這種技術使您能夠讀取的圖像數據的尺寸和類型在內存分配以前。app

1 BitmapFactory.Options options = new BitmapFactory.Options();
2 options.inJustDecodeBounds = true;
3 BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
4 int imageHeight = options.outHeight;
5 int imageWidth = options.outWidth;
6 String imageType = options.outMimeType;

爲了不java.lang.OutOfMemory異常,檢查解碼前的位圖的尺寸,除非您絕對信任的來源,以提供可預見的大小的圖像數據,適合有限的內存空間。less

 加載到內存中的一個縮減版本

如今的圖像尺寸是已知的,它們能夠被用來決定是否應加載到內存或二次採樣的版本,而不是應裝入完整的圖像。這裏有一些要考慮的因素:oop

  • 估計載入一張完整圖像的內存使用
  • 你願意投入到這個圖片加載應用程序的任何其餘內存要求的內存量。
  • 圖像要加載到的目標的ImageView或UI組件的尺寸。
  • 當前設備的屏幕大小和密度

例如,沒有必要把一個1024×768像素的圖像加載到內存中,若是它最終會被顯示在一個ImageView 128×96像素的縮略圖。告訴圖像解碼器,加載到內存中的一個較小的版本,設置BitmapFactory.Options對象中的inSampleSize。例如,與2048×1536分辨率的圖像,設置其inSampleSize爲4(即Width爲1/4,Height爲1/4,整個圖像大小爲1/16)將產生一個約512×384的位圖。載入到內存使用完整的圖像(假設ARGB_8888位圖配置)0.75MB,而超過12MB。這裏有一個方法來計算的樣本大小目標的寬度和高度上的值:性能

01 public static int calculateInSampleSize(
02             BitmapFactory.Options options, int reqWidth, int reqHeight) {
03     // 圖像原始高度和寬度
04     final int height = options.outHeight;
05     final int width = options.outWidth;
06     int inSampleSize = 1;
07   
08     if (height > reqHeight || width > reqWidth) {
09         if (width > height) {
10             inSampleSize = Math.round((float)height / (float)reqHeight);
11         } else {
12             inSampleSize = Math.round((float)width / (float)reqWidth);
13         }
14     }
15     return inSampleSize;
16 }

注意: inSampleSize 設置爲2的平方則編碼速度更快更高效。不過,若是你打算在內存或磁盤上的緩存調整過大小的版本,它一般仍是值得解碼到最合適的圖像尺寸,以節省空間。編碼

設置爲true inJustDecodeBounds使用這種方法,首先解碼,經過選項,而後解碼再次使用新inSampleSize值並inJustDecodeBounds設置爲false:spa

01 public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
02         int reqWidth, int reqHeight) {
03   
04     // 首先設置 inJustDecodeBounds=true 來檢查尺寸
05     final BitmapFactory.Options options = new BitmapFactory.Options();
06     options.inJustDecodeBounds = true;
07     BitmapFactory.decodeResource(res, resId, options);
08   
09     // 計算壓縮比例
10     options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
11   
12     // 設置inJustDecodeBounds爲false
13     options.inJustDecodeBounds = false;
14     return BitmapFactory.decodeResource(res, resId, options);
15 }

這種方法使很容易地裝入一個ImageView顯示一個100×100像素的縮略圖任意大尺寸位圖,在下面的示例代碼所示:

1 mImageView.setImageBitmap(
2   
3     decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

,你能夠按照一個相似的過程,使用不一樣的BitmapFactory.decode*方法來編碼其餘來源的圖像。
本文固定連接地址:
翻譯:Android解決大圖片內存溢出

相關文章
相關標籤/搜索