1 . 為了處理安卓中Bitmap圖片尺寸過(guò)大,導(dǎo)致內(nèi)存OOM,我們一般會(huì)對(duì)Bitmap處理一下,一般處理分為兩步。
- 第一步,獲取原始Bitmap的尺寸信息,然后我們?cè)O(shè)置一些相關(guān)配置,來(lái)盡量壓縮圖片
//這個(gè)函數(shù)就是相關(guān)配置Bitmap信息
BitmapFactory.Options options = new BitmapFactory.Options();
//這個(gè)表示,我們?cè)趧?chuàng)建bitmap時(shí),只獲取相關(guān)參數(shù),不生成bitmap對(duì)象
options.inJustDecodeBounds = true;
//設(shè)置圖片色彩模式,也有RGB_565,ARGB_8888表示每個(gè)像素占4個(gè)字節(jié),RGB_565表示每個(gè)像素占2個(gè)字節(jié)
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
//對(duì)圖片寬高進(jìn)行壓縮,如果值為2,則表示圖片寬高分別為1/2,像素則減少了原始的1/4
//一般來(lái)說(shuō)這個(gè)samplesize可以有我們自己計(jì)算
options.inSampleSize = 2;
下面是一個(gè)完整的代碼,只計(jì)算配置信息,不生成bitmap
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inPreferredConfig = Bitmap.Config.RGB_565;
//執(zhí)行這個(gè)方法,我們獲取到了option相關(guān)參數(shù)
BitmapFactory.decodeResource(getResources(), R.drawable.unnamed, options);
//計(jì)算samplesize ,根據(jù)你想要設(shè)置的寬高和原始圖片比較,
//當(dāng)然你也可以隨便設(shè)置,2,3,4都行
int sampleSize = calculateSampleSize(options, 400, 400);
private int calculateSampleSize(BitmapFactory.Options options, int reqW, int reqH) {
int sampleSize = 1;
int real_h = options.outHeight;
int real_w = options.outWidth;
if (real_h > reqH || real_w > reqW) {
int sam_h = Math.round((float) real_w / (float) real_h);
int sam_w = Math.round((float) real_w / (float) reqW);
sampleSize = Math.min(sam_h, sam_w);
}
return sampleSize;
}
- 第二部,將上面計(jì)算優(yōu)化過(guò)的Option參數(shù),傳入到Bitmap的創(chuàng)建函數(shù),獲取優(yōu)化后的Bitmap對(duì)象
options.inJustDecodeBounds=false;
options.inSampleSize = sampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap real = BitmapFactory.decodeResource(getResources(), R.drawable.unnamed, options);
2 . bitmpa在內(nèi)存中計(jì)算,分兩種情況
- 情況一BitmapFactory.decodeResource()
我們這里放一張?jiān)枷袼?20*405的圖片分別到到mipmap xhdpi文件夾中和mipmap xxhdpi
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap real = BitmapFactory.decodeResource(getResources(), R.mipmap.unnamed, options);
1.inDensity 取決于文件夾也就是xxhdpi還是xhdpi像素密度。取決于TypedValue,可以看下BitmapFactory.decodeResource方法源碼。
2.inTargetDensity 取決于手機(jī)屏幕密度。
3.底層源碼中源碼會(huì)對(duì)bitmap進(jìn)行縮放,縮放系數(shù)就是=inTargetDensity/inDensity,
- 像素字節(jié)數(shù)取決于BitmapFactory.Options.Config.ARGB***的設(shè)置,ARGB_8888表示每個(gè)像素占4個(gè)字節(jié),RGB_565占2個(gè)字節(jié)
- 所以最終bitmap在內(nèi)存中大小為 size = (原始寬)x(原始高)x(inTargetDensity/inDensity)x(inTargetDensity/inDensity)x像素字節(jié)數(shù)
Log.d(TAG, "ffff: density = " + options.inDensity + " target = " + options.inTargetDensity + "" +
" size = " + real.getByteCount() + " w= " + real.getWidth() + " h = " + real.getHeight());
/xhdpi: density = 320 target = 420 size = 2010960 w= 945 h = 532
/xxhdpi: density = 480 target = 420 size = 892080 w= 630 h = 354
- 情況二 BitmapFactory.decodeStream()
我們從assets文件夾照片加載圖片,也可以從手機(jī)外部存儲(chǔ)加載,以文件流的形式導(dǎo)入
1.分析點(diǎn)進(jìn)去看BitmapFactory.decodeStream源碼可知,并由沒(méi)對(duì)Options.inTargetDensity和Options.inDensity進(jìn)行賦值,默認(rèn)都為0
2.像素字節(jié)數(shù)取決于BitmapFactory.Options.Config.ARGB***的設(shè)置,ARGB_8888表示每個(gè)像素占4個(gè)字節(jié),RGB_565占2個(gè)字節(jié)
3.所以此時(shí)bitmap在內(nèi)存中占據(jù)的大小=(原始寬)x(原始高)x像素字節(jié)數(shù)
BitmapFactory.Options options = new BitmapFactory.Options();
try {
InputStream bitmap=getAssets().open("unnamed.jpg");
Bitmap real=BitmapFactory.decodeStream(bitmap);
Log.d(TAG, "ffff: density = " + options.inDensity + " target = " + options.inTargetDensity + "" +
" size = " + real.getByteCount() + " w= " + real.getWidth() + " h = " + real.getHeight());
//打印信息: density = 0 target = 0 size = 1166400 w= 720 h = 405
} catch (IOException e) {
e.printStackTrace();
}
3 . bitmpa.getByteCount vs bitmpa.getAllocationByteCount區(qū)別
- 這兩個(gè)方法都是計(jì)算bitmap占據(jù)內(nèi)存大小
- getAllocationByteCount這個(gè)方法Added in API level 19 ,默認(rèn)情況這兩個(gè)返回結(jié)果相同,所以我們SD大于19時(shí),計(jì)算Bitmap大小最好用這個(gè)方法
假設(shè)內(nèi)存已經(jīng)存在bitmap1 ,大小1234,此時(shí)我有新建了一個(gè)bitmap2 其實(shí)就是對(duì)bitmap1縮小了一倍。
這時(shí)因?yàn)榘沧恳呀?jīng)支持對(duì)Bitmap的復(fù)用,完全沒(méi)必要重新去在建立一個(gè)bitmap對(duì)象,浪費(fèi)性能重新計(jì)算和編碼bitmap
我們直接復(fù)用bitmap1,在進(jìn)行處理復(fù)用處理之后,此時(shí)Bitmap2對(duì)象的大小getByteCount 可能等于500,但是getAllocationByteCount一定等于1234