Bitmap疑惑

Bitmap是Android中的大頭饶米,下面記錄自己在Bitmap理解錯(cuò)誤的地方

1. BitmapFactory主要提供四個(gè)方法加載Bitmap:
public static Bitmap decodeFile(String pathName, Options opts);

public static Bitmap decodeResource(Resources res, int id, Options opts);

public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts);

public static Bitmap decodeStream(@Nullable InputStream is, @Nullable Rect outPadding,
@Nullable Options opts)
2. BimapFactory.Options提供了對(duì)圖片加載解析策略,主要使用到的參數(shù)有:
  • inBitmap 背蟆、inMutable
    用于實(shí)現(xiàn)Bitmap的復(fù)用,inBitmap賦一個(gè)允許復(fù)用的bitmap

  • inJustDecodeBounds
    如果inJustDecodeBounds設(shè)置為true,decode方法不會(huì)生成Bitmap對(duì)象谱俭,而僅僅是讀取該圖片的尺寸和類型信息笙纤,設(shè)置在outWidth、outHeight

  • inSampleSize
    圖片采樣率

  • inPreferredConfig
    RGB_565 ARGB_8888

  • inDensity
    設(shè)置位圖的像素密度

  • inTargetDensity
    設(shè)置屏幕密度

  • inScaled
    是否支持縮放突委,默認(rèn)是true
    當(dāng)inScale為true時(shí),且inDenstiy和inTargetDensity也不為0時(shí),位圖將在加載時(shí)時(shí)放縮到inTargetDensity
    放縮規(guī)則 縮放系數(shù) scale= inTargetDensity/inDesity

  • int outWidth
    圖片的原始寬度

  • int outHeight
    圖片的原始高度

3.Bitmap 加載大圖

Bitmap利用BitmapFactory進(jìn)行加載柏卤,但是容易導(dǎo)致OOM,為了避免這種情況

  1. 獲取圖像原始尺寸

    Options提供了inJustDecodeBounds匀油,當(dāng)inJustDecodeBounds為true缘缚,可以不生成bitmap,只讀取該圖片的尺寸和類型信息

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher, options);
int width = options.outWidth;
int height = options.outHeight;
  1. 計(jì)算inSampleSize

    inSampleSize設(shè)置圖像采樣率敌蚜,

    inSampleSize默認(rèn)是1桥滨,取的是2的次數(shù) 冪,若非2次數(shù)冪弛车,會(huì)向下找到最接近的數(shù)齐媒,最小是1;

    當(dāng)inSampleSize為1時(shí)纷跛,采樣后的圖片大小和原來一樣喻括;

    當(dāng)inSampleSize為2時(shí),采樣后的圖片寬高均為原來的1/2贫奠,大小為原來的1/4唬血;

    所以在計(jì)算采樣率的時(shí)候, 我們?nèi)∧繕?biāo)長(zhǎng)寬的最大值來跟原始寬度和高度計(jì)算比例叮阅,選取一個(gè)較大的值刁品,這樣會(huì)減少過度的尺寸壓縮

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
       final int width = options.outWidth;
       final int height = options.outHeight;
       int inSampleSize = 1;

       if (height > reqHeight || width > reqWidth) {
           final int max = reqHeight > reqWidth ? reqHeight : reqWidth;
           final int heightRatio = Math.round((float) height / (float)max);
           final int widthRatio = Math.round((float) width / (float)max);

           inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;
       }

       return inSampleSize;
}
  1. 加載圖像
options.inJustDecodeBounds = false;
Bitmap src = BitmapFactory.decodeFile(pathName, options);
Bitmap dst = Bitmap.createScaledBitmap(src,reqWidth,reqHeight, false);
if (src != dst) {
  src.recycle();
}
4. ARGB8888 RGB565區(qū)別

Bitmap.Config 有四種類型:

  • ALPHA_8:只有透明度,沒有顏色值浩姥,只有 A 通道挑随,占 8 位,1 個(gè)字節(jié)勒叠。每個(gè)像素點(diǎn)占用 1 個(gè)字節(jié)的大卸蛋ぁ膏孟;

  • ARGB_4444 :ARGB四個(gè)通道的值都是 4 位,占16位拌汇,2個(gè)字節(jié)柒桑。每個(gè)像素點(diǎn)占用2個(gè)字節(jié)大小噪舀;

  • ARGB_8888:ARGB四個(gè)通道的值都是 8位魁淳,占32位,4個(gè)字節(jié)与倡。每個(gè)像素點(diǎn)占用4個(gè)字節(jié)大薪绻洹;

  • RGB_565:沒有A通道纺座,R通道是5位息拜,G通道是6位,B通道是5位净响,占16位少欺,2個(gè)字節(jié)。每個(gè)像素點(diǎn)占用2個(gè)字節(jié)大胁鱿汀赞别;

5. Bitmap的內(nèi)存大小

之前一直以為Bitmap計(jì)算內(nèi)存大小很簡(jiǎn)單,例如格式是RGB_565配乓,內(nèi)存大小 = 寬度 * 高度 * 2字節(jié)氯庆,其實(shí)還是密度Density有關(guān),在談?wù)撚?jì)算內(nèi)存大小之前扰付,先看Android的DPI

(1) DPI

DPI(Dots Per Inch)每英寸有多少個(gè)像素點(diǎn)堤撵,用對(duì)角線斜邊的像素點(diǎn) 除以 斜邊的長(zhǎng)度

(2) dp(dip)

DPI是以像素點(diǎn)px來計(jì)算,而Android則是以dp(dip)來測(cè)算長(zhǎng)度單位羽莺,他的計(jì)算跟density有關(guān)实昨,而density跟DPI有關(guān)。詳細(xì)看后面的例子盐固。

(3) density

density 手機(jī)像素密度荒给,以單位英寸160個(gè)像素作為參考標(biāo)準(zhǔn)的:density = DPI / 160

也就是說在DPI為160的情況,1px = 1dp刁卜。

dp = dpi / 160 * px = density * px

這里有點(diǎn)凌亂志电,可以再想想,通過代碼獲取density:

context.getResources().getDisplayMetri  cs().density 

(4) 在drawable加載時(shí)候的圖片內(nèi)存大小

每個(gè)手機(jī)的分辨率都不一樣蛔趴,但是系統(tǒng)會(huì)選擇一個(gè)統(tǒng)一的DPI挑辆,如320、480,比如某個(gè)手機(jī)計(jì)算出來的DPI是445鱼蝉,但實(shí)際會(huì)選擇480為系統(tǒng)DPI

Android 中的drawable分成多個(gè)目錄洒嗤,不同DPI的系統(tǒng)會(huì)優(yōu)先選擇不同的目錄的資源:

在這里插入圖片描述

默認(rèn)的drawable是對(duì)應(yīng)mdpi,例如當(dāng)dpi為120時(shí)魁亦,會(huì)優(yōu)先使用drawable-ldpi目錄下的資源渔隶。

假如手機(jī)dpi是480,加載對(duì)應(yīng)dpi 480 的xxhdpi下面的圖片洁奈,圖片格式為RGB_565间唉,
則對(duì)應(yīng)的bitmap在內(nèi)存大小是:圖寬 * 圖高 * 2字節(jié)

假如手機(jī)dpi是480,加載對(duì)應(yīng)dpi 240 的hdpi下面的圖片利术,圖片格式為RGB_565终吼,系統(tǒng)會(huì)認(rèn)為你的圖片太小,需要擴(kuò)大 480 / 240 = 2倍
則對(duì)應(yīng)的bitmap在內(nèi)存大小是:圖寬 * 圖高 * 480 / 240 * 2字節(jié)

所以在drawable下面加載圖片的大小是跟系統(tǒng)DPI與drawable位置有關(guān)氯哮。

bitmap內(nèi)存大小 = 寬度 * 高度 * 系統(tǒng)的DPI / 目錄對(duì)應(yīng)的DPI * 圖片像素點(diǎn)的單位字節(jié)數(shù)

bitmap內(nèi)存大小 = 寬度 * 高度 * inDensity / inTargetDensity * 圖片像素點(diǎn)的單位字節(jié)數(shù)。

在Bitmap的Option中商佛,inDenstity表示圖像的密度喉钢、inTargetDensity表示屏幕的密度,因此在加載圖片的時(shí)候良姆,我們需要將圖像拉伸到inTargetDensity的密度肠虽,所以拉伸的倍數(shù) = inTargetDensity / inDenstity;

當(dāng)inScale為true玛追,表示支持拉伸且inDenstity税课、inTargetDensity都不為0的情況下,則

圖片的內(nèi)存大小 = 寬度 * 高度 * 目標(biāo)密度 / 原始密度 * 圖片像素點(diǎn)的單位字節(jié)數(shù)

圖片的內(nèi)存大小 = 寬度 * 高度 * inTargetDensity / inDenstity * 圖片像素點(diǎn)的單位字節(jié)數(shù)


(5) sdcard加載圖像的內(nèi)存大小

通過sdcard加載痊剖,默認(rèn)的 inDensity和inTargetDensity是0韩玩,所以

圖片的內(nèi)存大小 = 寬度 * 高度 * 圖片像素點(diǎn)的單位字節(jié)數(shù)

5. Bitmap壓縮

Bitmap提供了compress()進(jìn)行質(zhì)量壓縮,圖像壓縮率范圍是0到100陆馁, 0表示壓縮100%找颓,100表示不壓縮。

他跟inSampleSize壓縮不一樣叮贩,inSampleSize是尺寸壓縮击狮,質(zhì)量壓縮是在保持像素的前提下改變圖片的位深及透明度等,來達(dá)到壓縮圖片的目的益老,壓縮后的圖片大小可能會(huì)變小彪蓬,但是加載成bitmap后占用的內(nèi)存是不變的,寬高也不會(huì)改變捺萌,不適用于減少Bimap占用的內(nèi)存档冬。

6. Bitmap復(fù)用

Options提供了inMutable、inBitmap 進(jìn)行Bitmap的復(fù)用,需要設(shè)置inMutable為true捣郊,inBitmap設(shè)置想復(fù)用的Bitmap辽狈。

所謂復(fù)用的意思,就是使用inBitmap參數(shù)前呛牲,每創(chuàng)建一個(gè)Bitmap對(duì)象都會(huì)分配一塊內(nèi)存刮萌,而使用了inBitmap后, Bitmap的內(nèi)存是被重新利用的娘扩,多個(gè)Bitmap可以共用一塊內(nèi)存着茸。

Bitmap復(fù)用具有一定的限制:

在Android 4.4之前,僅支持相同大小的bitmap琐旁,inSampleSize必須為1涮阔,而且必須采用jpeg或png格式。

在Android 4.4之后只有一個(gè)限制灰殴,就是被復(fù)用的bitmap尺寸要大于 新的bitmap敬特,簡(jiǎn)單來說就是大圖可以給小圖復(fù)用。

BitmapFactory.Options largeOption = new BitmapFactory.Options();
largeOption.inMutable = true; // 設(shè)置inMutable
Bitmap largeBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.large, largeOption)

BitmapFactory.Options smallOption = new BitmapFactory.Options();
smallOption.inBitmap = largeBitmap; // 設(shè)置inBitmap被復(fù)用的Bitmap
Bitmap smallBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.small, smallOption);
7.BitmapRegionDecoder

BitmapRegionDecoder支持顯示圖片的某一塊矩形區(qū)域,牺陶,參數(shù)為Rect伟阔,作用是大圖片的部分區(qū)域顯示,還可以結(jié)合手勢(shì)控制器GestureDetector來控制圖片顯示的區(qū)域

8.參考

http://www.reibang.com/p/4a0b070d56af

http://blog.qiji.tech/archives/2581

https://blog.csdn.net/mylizhimin/article/details/53462653

http://www.reibang.com/p/c545f2a6cafc

https://juejin.im/entry/57c79e95128fe100695901b1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掰伸,一起剝皮案震驚了整個(gè)濱河市皱炉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狮鸭,老刑警劉巖合搅,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異歧蕉,居然都是意外死亡灾部,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門惯退,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梳猪,“玉大人,你說我怎么就攤上這事蒸痹〈好郑” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵叠荠,是天一觀的道長(zhǎng)匿沛。 經(jīng)常有香客問我,道長(zhǎng)榛鼎,這世上最難降的妖魔是什么逃呼? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任鳖孤,我火速辦了婚禮,結(jié)果婚禮上抡笼,老公的妹妹穿的比我還像新娘苏揣。我一直安慰自己,他們只是感情好推姻,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布平匈。 她就那樣靜靜地躺著,像睡著了一般藏古。 火紅的嫁衣襯著肌膚如雪增炭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天拧晕,我揣著相機(jī)與錄音隙姿,去河邊找鬼。 笑死厂捞,一個(gè)胖子當(dāng)著我的面吹牛输玷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播靡馁,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼欲鹏,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了奈嘿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤吞加,失蹤者是張志新(化名)和其女友劉穎裙犹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衔憨,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叶圃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了践图。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片掺冠。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖码党,靈堂內(nèi)的尸體忽然破棺而出德崭,到底是詐尸還是另有隱情,我是刑警寧澤揖盘,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布眉厨,位于F島的核電站,受9級(jí)特大地震影響兽狭,放射性物質(zhì)發(fā)生泄漏憾股。R本人自食惡果不足惜鹿蜀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望服球。 院中可真熱鬧茴恰,春花似錦、人聲如沸斩熊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽座享。三九已至婉商,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渣叛,已是汗流浹背丈秩。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留淳衙,地道東北人蘑秽。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像箫攀,于是被迫代替她去往敵國(guó)和親肠牲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 目錄介紹 01.如何計(jì)算Bitmap占用內(nèi)存1.1 如何計(jì)算占用內(nèi)存1.2 上面方法計(jì)算內(nèi)存對(duì)嗎1.3 一個(gè)像素占...
    楊充211閱讀 4,225評(píng)論 1 9
  • 在開發(fā)app時(shí),顯示一張本地圖片梢睛,這張圖片在加載時(shí)會(huì)占用大多內(nèi)存呢肥印?猜測(cè)占用內(nèi)存大小和以下幾個(gè)因素有關(guān): 設(shè)計(jì)師切...
    Coralline_xss閱讀 15,000評(píng)論 3 41
  • 越來越懶,好久沒寫了绝葡,今天我來記錄一下這個(gè)不聽話的小孩 放了三天假深碱,佳祿跟著姥爺回了老家,今早上連著打了...
    佳祿閱讀 83評(píng)論 0 0
  • 最近我可能是真的太閑太無聊了绞蹦,上個(gè)周竟然混入直播圈,開了兩次語音直播榜旦,然后我發(fā)現(xiàn)直接的言語懟粉比長(zhǎng)篇大論的毒雞湯管...
    如風(fēng)姑娘閱讀 4,411評(píng)論 0 1
  • 姓名:魏正君《六項(xiàng)精進(jìn)》第270期感謝2組公司:綿陽大北農(nóng)農(nóng)牧科技有限公司【日精進(jìn)打卡第379天】【知~學(xué)習(xí)】背誦...
    莫心莫肺閱讀 101評(píng)論 0 0