圖片加載<第二篇>:BitmapFactory.Options詳解

(1)常用屬性
BitmapFactory.Options options = new BitmapFactory.Options();

//默認值爲false,如果設置成true,那麼在解碼的時候就不會返回bitmap,即bitmap = null。
options.inJustDecodeBounds = false;

//可以複用之前用過的bitmap
options.inBitmap = null;

//是該bitmap緩存是否可變,如果設置爲true,將可被inBitmap複用
options.inMutable = true;


DisplayMetrics dm = getResources().getDisplayMetrics();
//表示這個bitmap的像素密度,當inDensity爲0時,系統默認賦值爲屏幕當前像素密度
options.inDensity = dm.densityDpi;

//表示要被畫出來時的目標像素密度,當inTargetDensity爲0時,系統默認賦值爲屏幕當前像素密度
options.inTargetDensity = options.inDensity;

//表示實際設備的像素密度
options.inScreenDensity = 0;

//這個參數可以改變bitmap分辨率大小,inSampleSize >= 1。
//當inSampleSize < 1時,inSampleSize就默認是1。
//假如:圖片的寬和高分別是width、height,那麼圖片解碼生成的bitmap的寬度是:width / inSampleSize,高度是:height / inSampleSize
//inSampleSize影響bitmap的分辨率,從而影響bitmap佔用內存的大小。
options.inSampleSize = 1;

//設置這個Bitmap是否可以被縮放,默認值是true,表示可以被縮放。
options.inScaled = true;
(2)圖片加載之前先計算圖片大小
Bitmap bitmap = BitmapFactory.decodeFile(FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "temp.jpg");

我們看一下上面的代碼,那是解碼一張本地圖片,解碼之後bitmap將佔用內存空間,如果bitmap太大導致app性能降低,甚至導致OOM發生,爲了防止這種現象,我們可以先計算本地圖片的分辨率:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(FileDirUtil.getInstance().getExternalStorageDirectory() + File.separator + "temp.jpg", options );
int imageHeight = options.outHeight;
Log.d("aaa", "圖片的高度:"+imageHeight);
int imageWidth = options.outWidth;
Log.d("aaa", "圖片的寬度:"+imageWidth);

inJustDecodeBounds設置true時,本地圖片解碼之後bitmap爲null,只計算圖片的寬度和高度。拿到圖片寬度和高度之後可以根據我們自己的策略是否放大或縮小圖片分辨率。

(3)使用inBitmap複用bitmap

inMutable設置成true,可以使當前bitmap對空間可被複用。

(4)像素密度分析

BitmapFactory.Options中與像素密度有關的主要有三個參數:inDensityinTargetDensityinScreenDensity

配合inScaled參數可以控制圖像縮放。

我們先看一下源碼

/**
 * Set the newly decoded bitmap's density based on the Options.
 */
private static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
    if (outputBitmap == null || opts == null) return;

    final int density = opts.inDensity;
    if (density != 0) {
        outputBitmap.setDensity(density);
        final int targetDensity = opts.inTargetDensity;
        if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
            return;
        }

        byte[] np = outputBitmap.getNinePatchChunk();
        final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
        if (opts.inScaled || isNinePatch) {
            outputBitmap.setDensity(targetDensity);
        }
    } else if (opts.inBitmap != null) {
        // bitmap was reused, ensure density is reset
        outputBitmap.setDensity(Bitmap.getDefaultDensity());
    }
}

inDensity的默認值爲0,會執行

outputBitmap.setDensity(Bitmap.getDefaultDensity());

bitmap的像素密度爲屏幕默認像素密度,相當於

DisplayMetrics dm = getResources().getDisplayMetrics();
//表示這個bitmap的像素密度,當inDensity爲0時,系統默認賦值爲屏幕當前像素密度
options.inDensity = dm.densityDpi;

當我們給inDensity取值時,就會走另一個分支,接下來纔是重點

當inTargetDensity=0或者inDensity=inTargetDensity或者inDensity=inScreenDensity時,圖像的像素密度是inDensity,否則,當inScaled = true或者圖像爲9Path圖片時,最終圖像的像素密度爲inTargetDensity。

inDensityinTargetDensityinScreenDensityinScaled配合使用可以修改像素密度,但是bitmap的大小是不變的,我們可以想象:

當bitmap的大小不變時,但像素密度變小了,那麼圖像的分辨率隨之增大,反之,圖像分辨率減小。

所以,我們可以調整像素密度來改變圖像分辨率。

(5)inSampleSize

修改像素密度只能修改圖像的分辨率,但不能改變bitmap大小。
而inSampleSize不僅可以修改分辨率,而且bitmap的大小也隨便變化。

假如默認情況(inSampleSize = 1)下,圖像的分辨率是205x205,佔用內存0.16031265M,那麼如果將inSampleSize 設置成2,那麼分辨率的寬和高分別除以2,佔用的內存也會變小,最終圖像的分辨率是103x103,佔用內存爲0.040470123M,bitmap大小整整縮小了4倍。

(6)設置彩色模式
options.inPreferredConfig = Bitmap.Config.ARGB_8888;

比較簡單,只有一句話。

ARGB_8888: 圖像默認模式,有ARGB四個顏色通道,每個通道佔8位。

ARGB_4444: 已被棄用,有ARGB四個顏色通道,每個通道佔4位。

RGB_565: 屏幕默認顏色模式,有RGB三個顏色通道。

ALPHA_8: 單通道,只有透明度通道。

RGBA_F16HARDWARE是Android 8.0新增的,目前用的比較少。

(7)獲取圖像的Mime類型
options.outMimeType
(8)設置緩衝區大小
//設置緩存區,如果不設置默認爲16M
options.inTempStorage = new byte[1024 * 1024 * 16];

如果不設置,那麼默認爲16M。

(9)其他方法
//這個值和抖動解碼有關,默認值爲false,表示不採用抖動解碼。在Android N 之後已被廢棄。
options.inDither = true;

//這個值表示是否在解碼時圖片有更高的品質,僅用於JPEG格式。如果設置爲true,則圖片會有更高的品質,但是會解碼速度會很慢。
//在Android N 之後已被廢棄。
options.inPreferQualityOverSpeed = true;

//設置爲true時,表示空間不夠是否可以被釋放。和inInputShareable一起使用。在Android5.0後被棄用。
options.inPurgeable = false;

//設置爲true時,後者表示是否可以共享引用。和inPurgeable一起使用。在Android5.0後被棄用。
options.inInputShareable = false;

//在Android N 之後已被廢棄
options.mCancel = false;

以上這些方法在高版本API上已被棄用,所以就不用研究了。

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