Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的縮略圖加載-不浪費一點多余的內存

Android中的縮略圖加載-不浪費一點多余的內存

編輯:關於Android編程

 

1. Why,為什麼要加載縮略圖?

有的時候不需要展示原圖,只需展示圖片的縮略圖,可以節省內存。比如:網易新聞中的圖片浏覽,左邊展示的小獅子圖片就是一個縮略圖,點擊這個圖片,才會展示原圖。

\ \

2. How,怎麼做呢?

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html給出了一個方法,可以加載一個圖片的縮略圖。
BitmapFactory#decodeFile (String pathName, BitmapFactory.Options opts),opts可以指定inJustDecodeBounds和inSampleSize兩個參數。當指定inJustDecodeBounds時候,只解析圖片的長度和寬度,不載入圖片。當指定inSampleSize的時候,會根據inSampleSize載入一個縮略圖。 比如inSampleSize=4,載入的縮略圖是原圖大小的1/4。
要設置inSampleSize是多少呢?假設原圖是1500x700的,我們給縮略圖留出的空間是100x100的。那麼inSampleSize=min(1500/100, 700/100)=7。我們可以得到的縮略圖是原圖的1/7。這裡如果你要問15:7的圖片怎麼顯示到1:1的區域內,請去看ImageView的scaleType屬性。
但是事實沒有那麼完美,雖然設置了inSampleSize=7,但是得到的縮略圖卻是原圖的1/4,原因是inSampleSize只能是2的整數次冪,如果不是的話,向下取得最大的2的整數次冪,7向下尋找2的整數次冪,就是4。
怎麼才能不浪費內存呢?大熊同學找到一個方法:Bitmap#createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter),該方法可以將一個Bitmap生成指定大小的BItmap,該方法可以放大圖片也可以縮小圖片。

最終縮略圖加載過程:

1. 使用inJustDecodeBounds,讀bitmap的長和寬。
2. 根據bitmap的長款和目標縮略圖的長和寬,計算出inSampleSize的大小。
3. 使用inSampleSize,載入一個大一點的縮略圖A
4. 使用createScaseBitmap,將縮略圖A,生成我們需要的縮略圖B。
5. 回收縮略圖A。

 

3. Notice,需要注意的事情

 

createScaseBitmap如果原圖和目標縮略圖大小一致,那麼不會生成一個新的bitmap直接返回bitmap,因此,回收的時候,要判斷縮略圖A是否就是縮略圖B,如果說是的話,不要回收。

4. 代碼

 

/**
 * http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
 */
public class BitmapUtils {
    private static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    // 如果是放大圖片,filter決定是否平滑,如果是縮小圖片,filter無影響
    private static Bitmap createScaleBitmap(Bitmap src, int dstWidth,
            int dstHeight) {
        Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
        if (src != dst) { // 如果沒有縮放,那麼不回收
            src.recycle(); // 釋放Bitmap的native像素數組
        }
        return dst;
    }

    // 從Resources中加載圖片
    public static Bitmap decodeSampledBitmapFromResource(Resources res,
            int resId, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options); // 讀取圖片長款
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight); // 計算inSampleSize
        options.inJustDecodeBounds = false;
        Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 載入一個稍大的縮略圖
        return createScaleBitmap(src, reqWidth, reqHeight); // 進一步得到目標大小的縮略圖
    }

    // 從sd卡上加載圖片
    public static Bitmap decodeSampledBitmapFromFd(String pathName,
            int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        Bitmap src = BitmapFactory.decodeFile(pathName, options);
        return createScaleBitmap(src, reqWidth, reqHeight);
    }
}

5. 測試代碼

代碼下載鏈接 http://download.csdn.net/detail/u011267546/7485045

在drawable-xxhdpi目錄下,一共有四種大圖,每個平均5-6MB,一共22.9MB。如果原圖加載很容易就崩潰了。如果使用上面的方法加載的話,只加載了234KB。這裡說一下234KB怎麼來的,4個imageView,目標尺寸都是75dip*50dip,在我的手機GalaxyNexus上面,轉化為px之後是150px*100px=15000個像素,每個像素使用ARGB_8888方式存儲,需要4個字節。一張圖片需要15000*4=60000字節,一共有4個Bitmap,那麼就是60000*4=240000字節=234.375 KB。

 

如果是布滿一個屏幕,至少需要多少內存呢?我的手機是768*1280像素,ARGB_8888方式存儲,每個像素4個字節,那麼就是768*1280*4=3840KB=3.75MB。所以,緩存3屏幕圖像的話,也就11MB左右。做內緩存的時候,有必要考慮下這個問題。

 

\

  1. 上一頁:
  2. 下一頁: