標籤:
在網上看了不少文章,發現還是官方文檔介紹最詳細,把重要的東西簡單摘要出來。詳細可看官方文檔地址 ( http://www.bangchui.org/read.php?tid=9 ) 。
在應用中顯示圖片,如果不多加小心,很容易就會使應用因為異常“java.lang.OutofMemoryError:bitmap size exceeds VM budget”而導致crash。在android中載入圖片需要一定的技巧性,主要是因為:
1.通常裝置資源有限,安卓裝置給每個應用只分配16M的空間。當然很多裝置都為應用設定了更高的記憶體,下面這個文檔的3.7節中有介紹不同螢幕裝置應用需要的最小記憶體(http://source.android.com/compatibility/downloads.html)。
2.圖片通常很占記憶體。例如Galxy Nexus相機解析度高達2592x1936,如果圖片配置為ARGB_8888(2.3以後預設配置),載入一張照片就需要19M記憶體(2592x1936x4 bytes),會很快消耗完一個應用的記憶體。
3.安卓的UI中通常需要一下載入多張圖片,如ListView,ViewPager。
本文主要介紹怎麼高效地載入大圖而不至於使你的應用記憶體溢出。大圖通常會比螢幕尺寸大很多,然而載入一個高解析度的圖片並不能帶來多少視覺體驗,通過下面兩步可以載入一個壓縮尺寸的圖片就節省記憶體。
第一步,讀取圖片尺寸和類型。
BitmapFactory類提供了多個decoding方法(decodeByteArray(), decodeFile(), decodeResource(), 等)使可以通過各種資料來源建立Bitmap,這些方法會在bitmap構造時申請記憶體,對於大圖,這樣會很容易導致記憶體溢出。每種decode方法都有一個額外的標誌參數BitmapFactory.Options,設定它的inJustDecodeBounds屬性為true,可以避免decode時分配記憶體,返回的Bitmap對象是一個null值,但能得到圖片的原始高度、寬度和格式(儲存在option的outWidth,outHeight,outMimeType中)。通過這種方式,可以在構造圖片前獲得圖片屬性。下面是範例程式碼:
[java] view plaincopy
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
- int imageHeight = options.outHeight;
- int imageWidth = options.outWidth;
- String imageType = options.outMimeType;
為了避免記憶體溢出,最好在載入圖片前都對尺寸做檢查,除非你保證源圖片沒有大圖。
第二步,載入縮小後的圖片到記憶體。
現在知道了原圖片的尺寸,根據實際情況決定你要載入它縮小多少倍後的圖片。例如你用一個128x96的ImageView顯示一張1024x768的原圖,根本沒有必要把原圖讀載入到記憶體。載入一張縮小後的圖片到記憶體,只需要把BitmapFactory.Options對象的inSampleSize設為true,然後給inSampleSize設一個值就行了(可以理解inSampleSize為n,圖片就縮小到1/n大小)。
下面是一段載入圖片的一段範例程式碼
[java] view plaincopy
- public static int calculateInSampleSize(
- BitmapFactory.Options options, int reqWidth, int reqHeight) {
- // Raw height and width of image
- final int height = options.outHeight;
- final int width = options.outWidth;
- int inSampleSize = 1;
-
- if (height > reqHeight || width > reqWidth) {
- if (width > height) {
- inSampleSize = Math.round((float)height / (float)reqHeight);
- } else {
- inSampleSize = Math.round((float)width / (float)reqWidth);
- }
- }
- return inSampleSize;
- }
[java] view plaincopy
- public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
- int reqWidth, int reqHeight) {
-
- // First decode with inJustDecodeBounds=true to check dimensions
- final BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- BitmapFactory.decodeResource(res, resId, options);
-
- // Calculate inSampleSize
- options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
-
- // Decode bitmap with inSampleSize set
- options.inJustDecodeBounds = false;
- return BitmapFactory.decodeResource(res, resId, options);
- }
Android中高效的顯示圖片之一 ——載入大圖