新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應用 > Android高效加載大圖、多圖解決方案,有效避免程序OOM

Android高效加載大圖、多圖解決方案,有效避免程序OOM

作者: 時間:2018-09-05 來源:網(wǎng)絡(luò) 收藏

高效加載大圖片我們在編寫Android程序的時候經(jīng)常要用到許多圖片,不同圖片總是會有不同的形狀、不同的大小,但在大多數(shù)情況下,這些圖片都會大于我們程序所需要的大小。比如說系統(tǒng)圖片庫里展示的圖片大都是用手機攝像頭拍出來的,這些圖片的分辨率會比我們手機屏幕的分辨率高得多。大家應該知道,我們編寫的應用程序都是有一定內(nèi)存限制的,程序占用了過高的內(nèi)存就容易出現(xiàn)OOM(OutOfMemory)異常。我們可以通過下面的代碼看出每個應用程序最高可用內(nèi)存是多少。

本文引用地址:http://www.butianyuan.cn/article/201809/388514.htm

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

Log.d(TAG, Max memory is + maxMemory + KB);

復制代碼

因此在展示高分辨率圖片的時候,最好先將圖片進行壓縮。壓縮后的圖片大小應該和用來展示它的控件大小相近,在一個很小的ImageView上顯示一張超大的圖片不會帶來任何視覺上的好處,但卻會占用我們相當多寶貴的內(nèi)存,而且在性能上還可能會帶來負面影響。下面我們就來看一看,如何對一張大圖片進行適當?shù)膲嚎s,讓它能夠以最佳大小顯示的同時,還能防止OOM的出現(xiàn)。

BitmapFactory這個類提供了多個解析方法(decodeByteArray, decodeFile, decodeResource等)用于創(chuàng)建Bitmap對象,我們應該根據(jù)圖片的來源選擇合適的方法。比如SD卡中的圖片可以使用decodeFile方法,網(wǎng)絡(luò)上的圖片可以使用decodeStream方法,資源文件中的圖片可以使用decodeResource方法。這些方法會嘗試為已經(jīng)構(gòu)建的bitmap分配內(nèi)存,這時就會很容易導致OOM出現(xiàn)。為此每一種解析方法都提供了一個可選的BitmapFactory.Options參數(shù),將這個參數(shù)的inJustDecodeBounds屬性設(shè)置為true就可以讓解析方法禁止為bitmap分配內(nèi)存,返回值也不再是一個Bitmap對象,而是null。雖然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType屬性都會被賦值。這個技巧讓我們可以在加載圖片之前就獲取到圖片的長寬值和MIME類型,從而根據(jù)情況對圖片進行壓縮。如下代碼所示:

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;

復制代碼

為了避免OOM異常,最好在解析每張圖片的時候都先檢查一下圖片的大小,除非你非常信任圖片的來源,保證這些圖片都不會超出你程序的可用內(nèi)存?,F(xiàn)在圖片的大小已經(jīng)知道了,我們就可以決定是把整張圖片加載到內(nèi)存中還是加載一個壓縮版的圖片到內(nèi)存中。以下幾個因素是我們需要考慮的:

預估一下加載整張圖片所需占用的內(nèi)存。

為了加載這一張圖片你所愿意提供多少內(nèi)存。

用于展示這張圖片的控件的實際大小。

當前設(shè)備的屏幕尺寸和分辨率。

比如,你的ImageView只有128*96像素的大小,只是為了顯示一張縮略圖,這時候把一張1024*768像素的圖片完全加載到內(nèi)存中顯然是不值得的。那我們怎樣才能對圖片進行壓縮呢?通過設(shè)置BitmapFactory.Options中inSampleSize的值就可以實現(xiàn)。比如我們有一張2048*1536像素的圖片,將inSampleSize的值設(shè)置為4,就可以把這張圖片壓縮成512*384像素。原本加載這張圖片需要占用13M的內(nèi)存,壓縮后就只需要占用0.75M了(假設(shè)圖片是ARGB_8888類型,即每個像素點占用4個字節(jié))。下面的方法可以根據(jù)傳入的寬和高,計算出合適的inSampleSize值:

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 heightRatio = Math.round((float) height / (float) reqHeight);

final int widthRatio = Math.round((float) width / (float) reqWidth);

// 選擇寬和高中最小的比率作為inSampleSize的值,這樣可以保證最終圖片的寬和高

// 一定都會大于等于目標的寬和高。

inSampleSize = heightRatio widthRatio ? heightRatio : widthRatio;

}

return inSampleSize;

}

復制代碼

使用這個方法,首先你要將BitmapFactory.Options的inJustDecodeBounds屬性設(shè)置為true,解析一次圖片。然后將BitmapFactory.Options連同期望的寬度和高度一起傳遞到到calculateInSampleSize方法中,就可以得到合適的inSampleSize值了。之后再解析一次圖片,使用新獲取到的inSampleSize值,并把inJustDecodeBounds設(shè)置為false,就可以得到壓縮后的圖片了。

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,

int reqWidth, int reqHeight) {

// 第一次解析將inJustDecodeBounds設(shè)置為true,來獲取圖片大小

final BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(res, resId, options);

// 調(diào)用上面定義的方法計算inSampleSize值

options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// 使用獲取到的inSampleSize值再次解析圖片

options.inJustDecodeBounds = false;

return BitmapFactory.decodeResource(res, resId, options);

}

復制代碼

下面的代碼非常簡單地將任意一張圖片壓縮成100*100的縮略圖,并在ImageView上展示。

mImageView.setImageBitmap(

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


上一頁 1 2 下一頁

關(guān)鍵詞:

評論


相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉