高效地加載Bitmap

概述

現在的圖片是動輒幾M到幾十M,而系統分配給應用的內存有限,如果直接將原圖載入內存,這會導致Bitmap加載的時候很容易出現內存溢出(OOM)。 Bitmap高效加載的策略:根據圖片展示控件的尺寸,將圖片以一定的採樣率進行縮放後再加載。這樣就能降低內存佔用,從而在一定程度上避免OOM,並提高Bitmap加載時的性能。

Bitmap的加載方式

BitmapFactory提供了四類方法來加載Bitmap: decodeFile:從文件加載Bitmap decodeResource:從資源中加載Bitmap decodeStream:從輸入流中加載Bitmap decodeByteArray:從字節數組中加載Bitmap 這四類方法都分別有一個帶 BitmapFactory.Options參數的重載方法,通過對這個參數的配置從而達到高效加載Bitmap。

BitmapFactory.Options的屬性

inSampleSize

inSampleSize:即採樣率,通過對其設置,實現圖片的寬和高縮放。 當inSampleSize=1:採樣後的圖片大小爲圖片的原始大小。 當inSameleSize<1:按=1計算 當inSampleSize>1:採樣後的圖片將會縮小,縮放比例爲1 / (inSampleSize的2次方)。 inSampleSize取值:inSampleSize的取值應該總是2的指數,如1,2,4,8等,如果傳入的inSampleSize的值不爲2的指數,那麼系統會向下取整並選擇一個最接近2的指數來代替。比如3,系統會選擇2來代替。

示例:

一張2048x1536像素的圖片,採用ARGB_8888進行存儲,那麼內存大小2048 x 1536 x 4 = 12M,如果inSampleSize = 4,那麼採樣後的圖片內存大小:512 x 384 x 4 = 0.75M

inJustDecodeBounds

在計算圖片縮放比的時候,我們需要先獲取到圖片的原始寬高,通過設置 inJustDecodeBounds=true,就可以在不將圖片加載進內存的情況下,解析出圖片的寬高信息。計算出縮放比後,再設置 inJustDecodeBounds=false,根據縮放比加載縮放後的圖片。

高效加載Bitmap流程

  1. 將BitmapFactory.Options的 inJustDecodeBounds參數設爲 true並加載圖片。
  2. 從BitmapFactory.Options中取出圖片的原始寬高信息,它們對應 outWidthoutHeight參數。
  3. 根據採樣率的規則並結合目標View的所需大小計算出採樣率 inSampleSize
  4. 將BitmapFactory.Options的 inJustDecodeBounds參數設爲 false,然後重新加載圖片。

代碼實現:

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);

        // 重新加載圖片
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public 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;

            // 計算縮放比,是2的指數,
            // 取寬高的最小縮放比,如寬的縮放比爲2,高的縮放比爲4,那麼取2作爲整體的縮放比
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

使用:

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

參考鏈接

  1. https://www.jianshu.com/p/5f02db4a225d
  2. https://developer.android.google.cn/topic/performance/graphics/load-bitmap

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章