国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Bitmap優(yōu)化詳談

jone5679 / 1851人閱讀

摘要:上面的代碼沒用過因?yàn)槲沂枪潭▉砣拥臄?shù)據(jù),為什么這個(gè)壓縮方法叫采樣率壓縮是因?yàn)榕浜希全@取圖片的寬高這個(gè)過程就是取樣。

目錄介紹

01.如何計(jì)算Bitmap占用內(nèi)存

1.1 如何計(jì)算占用內(nèi)存

1.2 上面方法計(jì)算內(nèi)存對嗎

1.3 一個(gè)像素占用多大內(nèi)存

02.Bitmap常見四種顏色格式

2.1 什么是bitmap

2.2 Android常見是那種

2.3 常見四種顏色格式介紹

2.4 Bitmap到底有幾種顏色格式

03.Bitmap壓縮技術(shù)

3.1 質(zhì)量壓縮

3.2 采樣率壓縮

3.3 縮放法壓縮

04.Bitmap回收問題

4.1 recycle()方法

4.2 緩存原理

4.3 Bitmap的復(fù)用

05.Bitmap常見操作

5.1 Bitmap的壓縮方式

5.2 Bitmap如何復(fù)用

5.3 Bitmap使用API獲取內(nèi)存

5.4 該博客對應(yīng)測試項(xiàng)目地址

好消息

博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長期更新維護(hù)并且修正,持續(xù)完善……開源的文件是markdown格式的!同時(shí)也開源了生活博客,從12年起,積累共計(jì)50篇[近30萬字],轉(zhuǎn)載請注明出處,謝謝!

鏈接地址:https://github.com/yangchong2...

如果覺得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!

輪播圖封裝庫:https://github.com/yangchong2...

輕量級版本更新彈窗:https://github.com/yangchong2...

通知欄封裝庫:https://github.com/yangchong2...

01.如何計(jì)算Bitmap占用內(nèi)存

歡迎直接查看demo的壓縮效果,https://github.com/yangchong2...

1.1 如何計(jì)算占用內(nèi)存

如果圖片要顯示下Android設(shè)備上,ImageView最終是要加載Bitmap對象的,就要考慮單個(gè)Bitmap對象的內(nèi)存占用了,如何計(jì)算一張圖片的加載到內(nèi)存的占用呢?其實(shí)就是所有像素的內(nèi)存占用總和:

bitmap內(nèi)存大小 = 圖片長度 x 圖片寬度 x 單位像素占用的字節(jié)數(shù)

起決定因素就是最后那個(gè)參數(shù)了,Bitmap"常見有2種編碼方式:ARGB_8888和RGB_565,ARGB_8888每個(gè)像素點(diǎn)4個(gè)byte,RGB_565是2個(gè)byte,一般都采用ARGB_8888這種。那么常見的1080*1920的圖片內(nèi)存占用就是:1920 x 1080 x 4 = 7.9M

1.2 上面方法計(jì)算內(nèi)存對嗎

我看到好多博客都是這樣計(jì)算的,但是這樣算對嗎?有沒有哥們試驗(yàn)過這種方法正確性?我覺得看博客要對博主表示懷疑,論證別人寫的是否正確。更多詳細(xì)可以看我的GitHub:https://github.com/yangchong211

說出我的結(jié)論:上面1.1這種說法也對,但是不全對,沒有說明場景,同時(shí)也忽略了一個(gè)影響項(xiàng):Density。接下來看看源代碼。

inDensity默認(rèn)為圖片所在文件夾對應(yīng)的密度;inTargetDensity為當(dāng)前系統(tǒng)密度。

加載一張本地資源圖片,那么它占用的內(nèi)存 = width height nTargetDensity/inDensity nTargetDensity/inDensity 一個(gè)像素所占的內(nèi)存。

@Nullable
public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
        @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
    validate(opts);
    if (opts == null) {
        opts = new Options();
    }

    if (opts.inDensity == 0 && value != null) {
        final int density = value.density;
        if (density == TypedValue.DENSITY_DEFAULT) {
            opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
        } else if (density != TypedValue.DENSITY_NONE) {
            opts.inDensity = density;
        }
    }
    
    if (opts.inTargetDensity == 0 && res != null) {
        opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
    }
    
    return decodeStream(is, pad, opts);
}

正確說法,這個(gè)注意呢?計(jì)算公式如下所示

對資源文件:width height nTargetDensity/inDensity nTargetDensity/inDensity 一個(gè)像素所占的內(nèi)存;

別的:width height 一個(gè)像素所占的內(nèi)存;

1.3 一個(gè)像素占用多大內(nèi)存

Bitmap.Config用來描述圖片的像素是怎么被存儲(chǔ)的?

ARGB_8888: 每個(gè)像素4字節(jié). 共32位,默認(rèn)設(shè)置。

Alpha_8: 只保存透明度,共8位,1字節(jié)。

ARGB_4444: 共16位,2字節(jié)。

RGB_565:共16位,2字節(jié),只存儲(chǔ)RGB值。

02.Bitmap常見四種顏色格式 2.1 什么是bitmap

位圖文件(Bitmap),擴(kuò)展名可以是.bmp或者.dib。位圖是Windows標(biāo)準(zhǔn)格式圖形文件,它將圖像定義為由點(diǎn)(像素)組成,每個(gè)點(diǎn)可以由多種色彩表示,包括2、4、8、16、24和32位色彩。位圖文件是非壓縮格式的,需要占用較大存儲(chǔ)空間。

2.2 Android常見是那種

在Gesture類中

在Notification類中

在fw源碼中bitmap圖片一般是以ARGB_8888(ARGB分別代表的是透明度,紅色,綠色,藍(lán)色,每個(gè)值分別用8bit來記錄,也就是一個(gè)像素會(huì)占用4byte,共32bit)來進(jìn)行存儲(chǔ)的。

2.3 常見四種顏色格式介紹

四種顏色格式如下所示

說明

在實(shí)際應(yīng)用中而言,建議使用ARGB_8888以及RGB_565。 如果你不需要透明度,選擇RGB_565,可以減少一半的內(nèi)存占用。

ARGB_8888:ARGB分別代表的是透明度,紅色,綠色,藍(lán)色,每個(gè)值分別用8bit來記錄,也就是一個(gè)像素會(huì)占用4byte,共32bit.

ARGB_4444:ARGB的是每個(gè)值分別用4bit來記錄,一個(gè)像素會(huì)占用2byte,共16bit.

RGB_565:R=5bit,G=6bit,B=5bit,不存在透明度,每個(gè)像素會(huì)占用2byte,共16bit

ALPHA_8:該像素只保存透明度,會(huì)占用1byte,共8bit.

2.4 Bitmap到底有幾種顏色格式

上面我說到了常見的四種,言下之意應(yīng)該不止四種,那到底有幾種呢?查看源碼可知,具體有6種類型。查看Bitmap源碼之Config配置。

配置Config.HARDWARE為啥異常,看下面源碼提示

03.Bitmap壓縮技術(shù) 3.1 質(zhì)量壓縮

質(zhì)量壓縮方法:在保持像素的前提下改變圖片的位深及透明度等,來達(dá)到壓縮圖片的目的,這樣適合去傳遞二進(jìn)制的圖片數(shù)據(jù),比如分享圖片,要傳入二進(jìn)制數(shù)據(jù)過去,限制500kb之內(nèi)。

1、bitmap圖片的大小不會(huì)改變

2、bytes.length是隨著quality變小而變小的。

/**
 * 第一種:質(zhì)量壓縮法
 * @param image     目標(biāo)原圖
 * @param maxSize   最大的圖片大小
 * @return          bitmap,注意可以測試以下壓縮前后bitmap的大小值
 */
public static Bitmap compressImage(Bitmap image , long maxSize) {
    int byteCount = image.getByteCount();
    Log.i("yc壓縮圖片","壓縮前大小"+byteCount);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    // 把ByteArrayInputStream數(shù)據(jù)生成圖片
    Bitmap bitmap = null;
    // 質(zhì)量壓縮方法,options的值是0-100,這里100表示原來圖片的質(zhì)量,不壓縮,把壓縮后的數(shù)據(jù)存放到baos中
    image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    int options = 90;
    // 循環(huán)判斷如果壓縮后圖片是否大于maxSize,大于繼續(xù)壓縮
    while (baos.toByteArray().length  > maxSize) {
        // 重置baos即清空baos
        baos.reset();
        // 這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中
        image.compress(Bitmap.CompressFormat.JPEG, options, baos);
        // 每次都減少10,當(dāng)為1的時(shí)候停止,options<10的時(shí)候,遞減1
        if(options == 1){
            break;
        }else if (options <= 10) {
            options -= 1;
        } else {
            options -= 10;
        }
    }
    byte[] bytes = baos.toByteArray();
    if (bytes.length != 0) {
        // 把壓縮后的數(shù)據(jù)baos存放到bytes中
        bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        int byteCount1 = bitmap.getByteCount();
        Log.i("yc壓縮圖片","壓縮后大小"+byteCount1);
    }
    return bitmap;
}


/**
 * 第一種:質(zhì)量壓縮法
 *
 * @param src           源圖片
 * @param maxByteSize   允許最大值字節(jié)數(shù)
 * @param recycle       是否回收
 * @return              質(zhì)量壓縮壓縮過的圖片
 */
public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize, final boolean recycle) {
    if (src == null || src.getWidth() == 0 || src.getHeight() == 0 || maxByteSize <= 0) {
        return null;
    }
    Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    byte[] bytes;
    if (baos.size() <= maxByteSize) {// 最好質(zhì)量的不大于最大字節(jié),則返回最佳質(zhì)量
        bytes = baos.toByteArray();
    } else {
        baos.reset();
        src.compress(Bitmap.CompressFormat.JPEG, 0, baos);
        if (baos.size() >= maxByteSize) { // 最差質(zhì)量不小于最大字節(jié),則返回最差質(zhì)量
            bytes = baos.toByteArray();
        } else {
            // 二分法尋找最佳質(zhì)量
            int st = 0;
            int end = 100;
            int mid = 0;
            while (st < end) {
                mid = (st + end) / 2;
                baos.reset();
                src.compress(Bitmap.CompressFormat.JPEG, mid, baos);
                int len = baos.size();
                if (len == maxByteSize) {
                    break;
                } else if (len > maxByteSize) {
                    end = mid - 1;
                } else {
                    st = mid + 1;
                }
            }
            if (end == mid - 1) {
                baos.reset();
                src.compress(Bitmap.CompressFormat.JPEG, st, baos);
            }
            bytes = baos.toByteArray();
        }
    }
    if (recycle && !src.isRecycled()){
        src.recycle();
    }
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount());
    return bitmap;
}


/**
 * 第一種:質(zhì)量壓縮法
 *
 * @param src     源圖片
 * @param quality 質(zhì)量
 * @param recycle 是否回收
 * @return 質(zhì)量壓縮后的圖片
 */
public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality, final boolean recycle) {
    if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
        return null;
    }
    Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    src.compress(Bitmap.CompressFormat.JPEG, quality, baos);
    byte[] bytes = baos.toByteArray();
    if (recycle && !src.isRecycled()) {
        src.recycle();
    }
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount());
    return bitmap;
}

3.2 采樣率壓縮

什么是采樣率壓縮?

設(shè)置inSampleSize的值(int類型)后,假如設(shè)為n,則寬和高都為原來的1/n,寬高都減少,內(nèi)存降低。上面的代碼沒用過options.inJustDecodeBounds = true;因?yàn)槲沂枪潭▉砣拥臄?shù)據(jù),為什么這個(gè)壓縮方法叫采樣率壓縮?是因?yàn)榕浜蟟nJustDecodeBounds,先獲取圖片的寬、高(這個(gè)過程就是取樣)。然后通過獲取的寬高,動(dòng)態(tài)的設(shè)置inSampleSize的值。當(dāng)inJustDecodeBounds設(shè)置為true的時(shí)候, BitmapFactory通過decodeResource或者decodeFile解碼圖片時(shí),將會(huì)返回空(null)的Bitmap對象,這樣可以避免Bitmap的內(nèi)存分配, 但是它可以返回Bitmap的寬度、高度以及MimeType。

/**
 * 第二種:按采樣大小壓縮
 *
 * @param src        源圖片
 * @param sampleSize 采樣率大小
 * @param recycle    是否回收
 * @return 按采樣率壓縮后的圖片
 */
public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) {
    if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
        return null;
    }
    Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = sampleSize;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    byte[] bytes = baos.toByteArray();
    if (recycle && !src.isRecycled()) {
        src.recycle();
    }
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
    Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount());
    return bitmap;
}


/**
 * 第二種:按采樣大小壓縮
 *
 * @param src       源圖片
 * @param maxWidth  最大寬度
 * @param maxHeight 最大高度
 * @param recycle   是否回收
 * @return 按采樣率壓縮后的圖片
 */
public static Bitmap compressBySampleSize(final Bitmap src, final int maxWidth, final int maxHeight, final boolean recycle) {
    if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
        return null;
    }
    Log.i("yc壓縮圖片","壓縮前大小"+src.getByteCount());
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    src.compress(Bitmap.CompressFormat.JPEG, 100, baos);
    byte[] bytes = baos.toByteArray();
    BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
    options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
    options.inJustDecodeBounds = false;
    if (recycle && !src.isRecycled()) {
        src.recycle();
    }
    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
    Log.i("yc壓縮圖片","壓縮后大小"+bitmap.getByteCount());
    return bitmap;
}

/**
 * 計(jì)算獲取縮放比例inSampleSize
 */
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 heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    final float totalPixels = width * height;
    final float totalReqPixelsCap = reqWidth * reqHeight * 2;
    while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) {
        inSampleSize++;
    }
    return inSampleSize;
}

3.3 縮放法壓縮

Android中使用Matrix對圖像進(jìn)行縮放、旋轉(zhuǎn)、平移、斜切等變換的。

Matrix提供了一些方法來控制圖片變換:Matrix調(diào)用一系列set,pre,post方法時(shí),可視為將這些方法插入到一個(gè)隊(duì)列。當(dāng)然,按照隊(duì)列中從頭至尾的順序調(diào)用執(zhí)行。其中pre表示在隊(duì)頭插入一個(gè)方法,post表示在隊(duì)尾插入一個(gè)方法。而set表示把當(dāng)前隊(duì)列清空,并且總是位于隊(duì)列的最中間位置。當(dāng)執(zhí)行了一次set后:pre方法總是插入到set前部的隊(duì)列的最前面,post方法總是插入到set后部的隊(duì)列的最后面

setTranslate(float dx,float dy):控制Matrix進(jìn)行位移。
setSkew(float kx,float ky):控制Matrix進(jìn)行傾斜,kx、ky為X、Y方向上的比例。
setSkew(float kx,float ky,float px,float py):控制Matrix以px、py為軸心進(jìn)行傾斜,kx、ky為X、Y方向上的傾斜比例。
setRotate(float degrees):控制Matrix進(jìn)行depress角度的旋轉(zhuǎn),軸心為(0,0)。
setRotate(float degrees,float px,float py):控制Matrix進(jìn)行depress角度的旋轉(zhuǎn),軸心為(px,py)。
setScale(float sx,float sy):設(shè)置Matrix進(jìn)行縮放,sx、sy為X、Y方向上的縮放比例。
setScale(float sx,float sy,float px,float py):設(shè)置Matrix以(px,py)為軸心進(jìn)行縮放,sx、sy為X、Y方向上的縮放比例。

縮放法壓縮工具類代碼

/**
 * 第三種:按縮放壓縮
 *
 * @param src                   源圖片
 * @param newWidth              新寬度
 * @param newHeight             新高度
 * @param recycle               是否回收
 * @return                      縮放壓縮后的圖片
 */
public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) {
    return scale(src, newWidth, newHeight, recycle);
}

public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) {
    return scale(src, scaleWidth, scaleHeight, recycle);
}

/**
 * 縮放圖片
 *
 * @param src                   源圖片
 * @param scaleWidth            縮放寬度倍數(shù)
 * @param scaleHeight           縮放高度倍數(shù)
 * @param recycle               是否回收
 * @return                      縮放后的圖片
 */
private static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) {
    if (src == null || src.getWidth() == 0 || src.getHeight() == 0) {
        return null;
    }
    Matrix matrix = new Matrix();
    matrix.setScale(scaleWidth, scaleHeight);
    Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
    if (recycle && !src.isRecycled()) {
        src.recycle();
    }
    return ret;
}

04.Bitmap回收問題 4.1 recycle()方法

如何調(diào)用這個(gè)recycle()方法

if (bitmap != null && !bitmap.isRecycled()) {
    bitmap.recycle();
    bitmap = null;
}

思考以下,為何調(diào)用recycle()需要做非空判斷?這里可以引出bitmap系統(tǒng)回收功能。小楊我如果分析不對,歡迎反饋。

首先看看源碼……順便翻一下該方法的注釋!我是用有道翻譯的,大意如下:釋放與此位圖關(guān)聯(lián)的本機(jī)對象,并清除對像素?cái)?shù)據(jù)的引用。這將不會(huì)同步釋放像素?cái)?shù)據(jù);如果沒有其他引用,它只允許垃圾收集。位圖被標(biāo)記為“死”,這意味著如果調(diào)用getPixels()或setPixels(),它將拋出異常,并且不會(huì)繪制任何東西。此操作不能反轉(zhuǎn),因此只有在確定沒有進(jìn)一步使用位圖的情況下才應(yīng)調(diào)用該操作。這是一個(gè)高級調(diào)用,通常不需要調(diào)用,因?yàn)楫?dāng)沒有對此位圖的引用時(shí),普通GC進(jìn)程將釋放此內(nèi)存。

public void recycle() {
    if (!mRecycled && mNativePtr != 0) {
        if (nativeRecycle(mNativePtr)) {
            // return value indicates whether native pixel object was actually recycled.
            // false indicates that it is still in use at the native level and these
            // objects should not be collected now. They will be collected later when the
            // Bitmap itself is collected.
            mNinePatchChunk = null;
        }
        mRecycled = true;
    }
}

通常不需要調(diào)用?這是為啥?

在Android3.0以后Bitmap是存放在堆中的,只要回收堆內(nèi)存即可。官方建議我們3.0以后使用recycle()方法進(jìn)行回收,該方法可以不主動(dòng)調(diào)用,因?yàn)槔厥掌鲿?huì)自動(dòng)收集不可用的Bitmap對象進(jìn)行回收。

那么何是進(jìn)行回收呢?這里面涉及到bitmap的緩存算法,還有GC回收垃圾機(jī)制。關(guān)于GC回收機(jī)制可以看我這篇博客:https://blog.csdn.net/m0_3770...

大概就是移除最少使用的緩存和使用最久的緩存,先說出結(jié)論,下來接著分析!

4.2 緩存原理

LruCache原理

LruCache是個(gè)泛型類,內(nèi)部采用LinkedHashMap來實(shí)現(xiàn)緩存機(jī)制,它提供get方法和put方法來獲取緩存和添加緩存,其最重要的方法trimToSize是用來移除最少使用的緩存和使用最久的緩存,并添加最新的緩存到隊(duì)列中。

4.3 Bitmap的復(fù)用

Android3.0之后,并沒有強(qiáng)調(diào)Bitmap.recycle();而是強(qiáng)調(diào)Bitmap的復(fù)用。

使用LruCache對Bitmap進(jìn)行緩存,當(dāng)再次使用到這個(gè)Bitmap的時(shí)候直接獲取,而不用重走編碼流程。

Android3.0(API 11之后)引入了BitmapFactory.Options.inBitmap字段,設(shè)置此字段之后解碼方法會(huì)嘗試復(fù)用一張存在的Bitmap。這意味著Bitmap的內(nèi)存被復(fù)用,避免了內(nèi)存的回收及申請過程,顯然性能表現(xiàn)更佳。

使用這個(gè)字段有幾點(diǎn)限制:

聲明可被復(fù)用的Bitmap必須設(shè)置inMutable為true;

Android4.4(API 19)之前只有格式為jpg、png,同等寬高(要求苛刻),inSampleSize為1的Bitmap才可以復(fù)用;

Android4.4(API 19)之前被復(fù)用的Bitmap的inPreferredConfig會(huì)覆蓋待分配內(nèi)存的Bitmap設(shè)置的inPreferredConfig;

Android4.4(API 19)之后被復(fù)用的Bitmap的內(nèi)存必須大于需要申請內(nèi)存的Bitmap的內(nèi)存;

Android4.4(API 19)之前待加載Bitmap的Options.inSampleSize必須明確指定為1。

05.Bitmap常見操作 5.1 Bitmap的壓縮方式

常見壓縮方法Api

Bitmap.compress(),質(zhì)量壓縮,不會(huì)對內(nèi)存產(chǎn)生影響;

BitmapFactory.Options.inSampleSize,內(nèi)存壓縮;

Bitmap.compress()

質(zhì)量壓縮,不會(huì)對內(nèi)存產(chǎn)生影響

它是在保持像素的前提下改變圖片的位深及透明度等,來達(dá)到壓縮圖片的目的,不會(huì)減少圖片的像素。進(jìn)過它壓縮的圖片文件大小會(huì)變小,但是解碼成bitmap后占得內(nèi)存是不變的。

BitmapFactory.Options.inSampleSize

內(nèi)存壓縮

解碼圖片時(shí),設(shè)置BitmapFactory.Options類的inJustDecodeBounds屬性為true,可以在Bitmap不被加載到內(nèi)存的前提下,獲取Bitmap的原始寬高。而設(shè)置BitmapFactory.Options的inSampleSize屬性可以真實(shí)的壓縮Bitmap占用的內(nèi)存,加載更小內(nèi)存的Bitmap。

設(shè)置inSampleSize之后,Bitmap的寬、高都會(huì)縮小inSampleSize倍。例如:一張寬高為2048x1536的圖片,設(shè)置inSampleSize為4之后,實(shí)際加載到內(nèi)存中的圖片寬高是512x384。占有的內(nèi)存就是0.75M而不是12M,足足節(jié)省了15倍。

備注:inSampleSize值的大小不是隨便設(shè)、或者越大越好,需要根據(jù)實(shí)際情況來設(shè)置。inSampleSize比1小的話會(huì)被當(dāng)做1,任何inSampleSize的值會(huì)被取接近2的冪值。

5.2 Bitmap如何復(fù)用

Bitmap復(fù)用的實(shí)驗(yàn),代碼如下所示,然后看打印的日志信息

從內(nèi)存地址的打印可以看出,兩個(gè)對象其實(shí)是一個(gè)對象,Bitmap復(fù)用成功;

bitmapReuse占用的內(nèi)存(4346880)正好是bitmap占用內(nèi)存(1228800)的四分之一;

getByteCount()獲取到的是當(dāng)前圖片應(yīng)當(dāng)所占內(nèi)存大小,getAllocationByteCount()獲取到的是被復(fù)用Bitmap真實(shí)占用內(nèi)存大小。雖然bitmapReuse的內(nèi)存只有4346880,但是因?yàn)槭菑?fù)用的bitmap的內(nèi)存,因而其真實(shí)占用的內(nèi)存大小是被復(fù)用的bitmap的內(nèi)存大小(1228800)。這也是getAllocationByteCount()可能比getByteCount()大的原因。

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void initBitmap() {
    BitmapFactory.Options options = new BitmapFactory.Options();
    // 圖片復(fù)用,這個(gè)屬性必須設(shè)置;
    options.inMutable = true;
    // 手動(dòng)設(shè)置縮放比例,使其取整數(shù),方便計(jì)算、觀察數(shù)據(jù);
    options.inDensity = 320;
    options.inTargetDensity = 320;
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_autumn_tree_min, options);
    // 對象內(nèi)存地址;
    Log.i("ycBitmap", "bitmap = " + bitmap);
    Log.i("ycBitmap", "ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount());
    // 使用inBitmap屬性,這個(gè)屬性必須設(shè)置;
    options.inBitmap = bitmap; options.inDensity = 320;
    // 設(shè)置縮放寬高為原始寬高一半;
    options.inTargetDensity = 160;
    options.inMutable = true;
    Bitmap bitmapReuse = BitmapFactory.decodeResource(getResources(), R.drawable.bg_kites_min, options);
    // 復(fù)用對象的內(nèi)存地址;
    Log.i("ycBitmap", "bitmapReuse = " + bitmapReuse);
    Log.i("ycBitmap", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount());
    Log.i("ycBitmap", "bitmapReuse:ByteCount = " + bitmapReuse.getByteCount() + ":::bitmapReuse:AllocationByteCount = " + bitmapReuse.getAllocationByteCount());

    //11-26 18:24:07.971 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap = android.graphics.Bitmap@9739bff
    //11-26 18:24:07.972 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 4346880:::bitmap:AllocationByteCount = 4346880
    //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse = android.graphics.Bitmap@9739bff
    //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 1228800:::bitmap:AllocationByteCount = 4346880
    //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse:ByteCount = 1228800:::bitmapReuse:AllocationByteCount = 4346880
}

5.3 Bitmap使用API獲取內(nèi)存

getByteCount()

getByteCount()方法是在API12加入的,代表存儲(chǔ)Bitmap的色素需要的最少內(nèi)存。API19開始getAllocationByteCount()方法代替了getByteCount()。

getAllocationByteCount()

API19之后,Bitmap加了一個(gè)Api:getAllocationByteCount();代表在內(nèi)存中為Bitmap分配的內(nèi)存大小。

public final int getAllocationByteCount() {
    if (mRecycled) {
        Log.w(TAG, "Called getAllocationByteCount() on a recycle()"d bitmap! "
                + "This is undefined behavior!");
        return 0;
    }
    return nativeGetAllocationByteCount(mNativePtr);
}

思考: getByteCount()與getAllocationByteCount()的區(qū)別?

一般情況下兩者是相等的;

通過復(fù)用Bitmap來解碼圖片,如果被復(fù)用的Bitmap的內(nèi)存比待分配內(nèi)存的Bitmap大,那么getByteCount()表示新解碼圖片占用內(nèi)存的大小(并非實(shí)際內(nèi)存大小,實(shí)際大小是復(fù)用的那個(gè)Bitmap的大小),getAllocationByteCount()表示被復(fù)用Bitmap真實(shí)占用的內(nèi)存大小(即mBuffer的長度)。

在復(fù)用Bitmap的情況下,getAllocationByteCount()可能會(huì)比getByteCount()大。

5.4 該博客對應(yīng)測試項(xiàng)目地址

歡迎直接查看demo的壓縮效果,https://github.com/yangchong2...

關(guān)于其他內(nèi)容介紹 01.關(guān)于博客匯總鏈接

1.技術(shù)博客匯總

2.開源項(xiàng)目匯總

3.生活博客匯總

4.喜馬拉雅音頻匯總

5.其他匯總

02.關(guān)于我的博客

我的個(gè)人站點(diǎn):www.yczbj.org,www.ycbjie.cn

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

簡書:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜馬拉雅聽書:http://www.ximalaya.com/zhubo...

開源中國:https://my.oschina.net/zbj161...

泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...

郵箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault頭條:https://segmentfault.com/u/xi...

掘金:https://juejin.im/user/593943...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/72445.html

相關(guān)文章

  • 詳談js防抖和節(jié)流

    摘要:本文會(huì)分別介紹什么是防抖和節(jié)流,它們的應(yīng)用場景,和實(shí)現(xiàn)方式。防抖和節(jié)流都是為了解決短時(shí)間內(nèi)大量觸發(fā)某函數(shù)而導(dǎo)致的性能問題,比如觸發(fā)頻率過高導(dǎo)致的響應(yīng)速度跟不上觸發(fā)頻率,出現(xiàn)延遲,假死或卡頓的現(xiàn)象。 本文由小芭樂發(fā)表 0. 引入 首先舉一個(gè)例子: 模擬在輸入框輸入后做ajax查詢請求,沒有加入防抖和節(jié)流的效果,這里附上完整可執(zhí)行代碼: 沒有防抖 ...

    shevy 評論0 收藏0
  • Deep In React 之詳談 React 16 Diff 策略(二)

    摘要:對于同一層級的一組子節(jié)點(diǎn),它們可以通過唯一進(jìn)行區(qū)分。基于以上三個(gè)前提策略,分別對以及進(jìn)行算法優(yōu)化。鏈表的每一個(gè)節(jié)點(diǎn)是,而不是在之前的虛擬節(jié)點(diǎn)。是當(dāng)前層的第一個(gè)節(jié)點(diǎn)。再次提醒,是的一層。 文章首發(fā)于個(gè)人博客 這是我 Deep In React 系列的第二篇文章,如果還沒有讀過的強(qiáng)烈建議你先讀第一篇:詳談 React Fiber 架構(gòu)(1)。 前言 我相信在看這篇文章的讀者一般都已經(jīng)了解...

    NSFish 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<