Android大尺寸圖片加載問題

對於大尺寸圖片加載,如何正常加載顯示且不發生OOM?

  • 圖片採樣,應用場景:圖片全部顯示在控件上
  • 圖片按區域加載,應用場景:高清巨圖,不允許壓縮,如世界地圖、清明上河圖

圖片採樣

圖片採樣的方法,是根據需要顯示圖片控件的大小對圖片進行壓縮顯示。

主要用法

1、根據控件的寬高與原圖的寬高的比例,計算出BitmapFactory.OptionsinSampleSize值。例如:

public static int calculateInSampleSize(int reqWidth, int reqHeight, BitmapFactory.Options options) {
    if (reqHeight == 0 || reqWidth == 0) {
        return 1;
    }

    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;

        // Calculate the largest inSampleSize value that is a power of 2 and
        // keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }

    Log.d(“TAG”, "calculateInSampleSize: " + inSampleSize);
    return inSampleSize;
}

第一、二個參數分別是顯示控件的寬度和高度,第三個參數是設置了inSampleSize的BitmapFactory.Options對象,設置inSampleSize爲2的冪是因爲解碼器最終會對非2的冪的數進行向下處理,獲取到最靠近2的冪的數。詳情參考inSampleSize的文檔。

2、然後在解析圖片文件時,傳入這個BitmapFactory.Options。例如

public static Bitmap getFitSampleBitmap(String filePath, int width, int height) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(filePath, options);
    //計算inSampleSize方法
    options.inSampleSize = calculateInSampleSize(width, height, options);
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(filePath, options);
}

第一個參數是圖片存放的路徑,第二、三個參數是顯示控件的寬度和高度

測試過程,查看Memory使用情況

1、沒有壓縮處理,內存佔用106M左右
沒有壓縮.png

2、inSampleSize=2,內部佔用46M左右
inSampleSize=2.png

從上面對比可以看出,經過圖片的採樣壓縮,內存使用大大降低,減少OOM的發生。

具體Demo可以參考Android 多種方式正確的加載圖像,有效避免oom

圖片按區域加載

對於世界地圖等高清巨圖,如果不壓縮,那麼按照原圖尺寸加載,屏幕肯定不夠,並且考慮內存的情況,不可能一次性將整圖加載到內存中,否則很容易發生OOM。如何解決這種問題,可以採用的方法:局部加載,讓圖片按區域加載,用到Android提供的類:

BitmapRegionDecoder

主要用法:

1、創建BitmapRegionDecoder對象

BitmapRegionDecoder提供了一系列的newInstance方法來構造對象,傳入需要處理的圖片,支持傳入文件路徑,文件描述符,文件的inputstrem等。

例如:

BitmapRegionDecoder bitmapRegionDecoder =
  BitmapRegionDecoder.newInstance(inputStream, false);

2、顯示指定的區域

bitmapRegionDecoder.decodeRegion(rect, options);

參數一是一個rect,指定顯示的區域,參數二是BitmapFactory.Options,可以控制圖片的inSampleSize, inPreferredConfig等。

具體Demo可以學習Android 高清加載巨圖方案 拒絕壓縮圖片,加上手勢移動,動態修改顯示的區域。

調試DEMO時,發現存在一個問題,初始化顯示setInputStream時,圖片只顯示一角,手勢移動沒有反應。

通過Debug,查到BitmapFactory.Options獲取圖片的寬高有問題,修改方式是直接通過BitmapRegionDecoder.getWidth和getHeight獲取寬高。

參考資料

1、Android 多種方式正確的加載圖像,有效避免oom

2、Android 高清加載巨圖方案 拒絕壓縮圖片

3、Android圖片尺寸與質量壓縮你用對了嗎?inSampleSize與quality的淺析

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