在寫本文之前,我還以為自己對android的bitmap很熟悉,直到自己親手寫代碼實踐,才發(fā)現(xiàn)自己錯了很多年。真是汗顏??!
Bitmap Config
首先,根據(jù)Android API 25的文檔簡要說明一下Android的Bitmap.Config以下4個選項
- ALPHA_8: 每個像素占用1字節(jié)(8位),存儲的是透明度信息。
- ARGB_4444: 每個像素占用2字節(jié)(4+4+4+4=16位),ARGB分別占用4位,支持alpha通道。
注:從API 13開始不推薦使用,在android 4.4上面,設(shè)置的ARGB_4444會被系統(tǒng)使用ARGB_8888替換 - ARGB_8888: 默認的選項,每像素占用4字節(jié),ARGB分別占8位,支持1600萬種顏色,質(zhì)量最高,當(dāng)然內(nèi)存占用也高。
- RGB_565: 每像素占用2字節(jié),RGB分別占5,6,5位。支持65535種顏色,不支持alpha。
| bitmap.config | ALPHA_8 | ARGB_4444 | ARGB_8888 | RGB_565 |
|---|---|---|---|---|
| bytes/pixel | 1 byte | 2 byte | 4 byte | 2 byte |
| alpha channel | 8 bit | 4 bit | 8 bit | not support |
PNG 格式
其次,簡要說一下png格式
- png 8: 支持不透明,索引色透明,alpha透明,最大支持256種顏色
- png 24: 不支持透明,支持1600萬種顏色
- png 32: 支持透明,其它同png 24,支持1600萬種顏色
bitmap內(nèi)存占用計算
第三,簡要說一下bitmap占用的內(nèi)存
Android中bitmap的內(nèi)存占用是跟圖片的尺寸(高和寬)相關(guān)。一張圖片的內(nèi)存占用大致的計算公式如下:
占用內(nèi)存 = 圖像像素總和(width x height)再 x 每像素(bitmap config)占用的字節(jié)數(shù)
以下是通過代碼準確計算
public static int getSizeInBytes(@Nullable Bitmap bitmap) {
if (bitmap == null) {
return 0;
}
// There's a known issue in KitKat where getAllocationByteCount() can throw an NPE. This was
// apparently fixed in MR1: http://bit.ly/1IvdRpd. So we do a version check here, and
// catch any potential NPEs just to be safe.
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
try {
return bitmap.getAllocationByteCount();
} catch (NullPointerException npe) {
// Swallow exception and try fallbacks.
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
return bitmap.getByteCount();
}
// Estimate for earlier platforms.
return bitmap.getWidth() * bitmap.getRowBytes();
}
以一張10241024的圖片為例,使用ARGB_8888,占用的內(nèi)存為10241024*4=4M。像現(xiàn)在的手機攝像頭動不動就是上千萬像素,拍出來的照片如果按默認的ARGB_8888 config加載,則至少是幾十M的內(nèi)存占用。
Android的圖片資源主要分兩部分:
- 一種是apk中自帶的,多為png格式,由系統(tǒng)加載,支持縮放,代碼中通過R.xxx引用,decode時使用的是默認的ARGB_8888選項,圖像質(zhì)量高;
- 另一種是網(wǎng)絡(luò)圖片或本地圖片,多為jpg格式,加載時一般使用第三方的圖片加載庫,為節(jié)省內(nèi)存decode時多為RGB_565選項。
平時都是這么用,也沒發(fā)現(xiàn)問題,優(yōu)化內(nèi)存占用時,一般也是從圖片的尺寸方面入手。不過最近優(yōu)化一個跟圖片相關(guān)的功能,在圖片尺寸無法縮放的條件下,只能通過更改bitmap config來降低內(nèi)存的占用。然后意外的發(fā)現(xiàn),導(dǎo)致顛覆了我的三觀。為此我特地寫了一個測試sample,代碼詳見github,特地創(chuàng)建了一張背景色透明,圖片內(nèi)容為A(黑色50%透明度)R(紅色)G(綠色)B(藍色)圖片,然后分別導(dǎo)出為:png8(alpha透明)、png24(不透明)、png32和jpeg(不透明)格式的圖,分別使用ALPHA_8, ARGB_4444, ARGB_8888, RGB_565四種config加載圖片,得到的實際結(jié)果如下(假設(shè)圖像總像素為X)。
實踐結(jié)果
運行截圖

結(jié)果統(tǒng)計
| bitmap.config | ALPHA_8 | ARGB_4444 | ARGB_8888 | RGB_565 |
|---|---|---|---|---|
|
41 |
2 X | 4 X |
42不 |
|
41 |
2 X | 4 X | 2 X |
|
41 |
2 X | 4 X |
42不 |
|
41 |
2 X | 4 X | 2 X |
請注意表格中帶刪除線的部分
- ALPHA_8:config占用的內(nèi)存竟然和ARGB_8888一樣,不是說每個像素占用1字節(jié)的么?
- RGB_565:在png8和png32中,圖片中的A都保持了50%的透明度,而且占用的內(nèi)存也和ARGB_8888一樣,不是說RGB_565不包含alpha么?不是說占用的內(nèi)存是ARGB_8888的一半么?
- ARGB_4444:在android 6.0上面,png8和png32看不見(全透明),png24和jpeg顯示為一塊黑色區(qū)域,在android 4.2上則顯示正常。
帶著上面的疑問,在網(wǎng)上進行了相關(guān)的搜索,也沒有找到答案。好吧,我是懵了,不知道各位看客如何?附上github上的示例工程:https://github.com/Jamling/BitmapConfig
本文永久鏈接: http://www.ieclipse.cn/2017/06/14/Android/Android-bitmap-config/ 未經(jīng)允許,禁止轉(zhuǎn)載,如有問題,請在我的博客原始頁面提交評論。