【Android 内存优化】Bitmap 内存占用计算 ( Bitmap 图片内存占用分析 | Bitmap 内存占用计算 | Bitmap 不同像素密度间的转换 )
文章目錄
- 一、Bitmap 內(nèi)存占用
- 二、Bitmap 內(nèi)存占用計(jì)算示例
- 三、Bitmap 內(nèi)存占用與像素密度
- 四、Bitmap 內(nèi)存占用與像素密度示例
一、Bitmap 內(nèi)存占用
在 Android 中 Bitmap 對(duì)象在內(nèi)存中存儲(chǔ)的的像素格式有兩種 : ARGB_8888 和 RGB_555 ;
① ARGB_8888 像素格式 : Alpha ( 透明度 ) , Red ( 紅 ) , Green ( 綠 ) , Blue ( 藍(lán) ) , 各占 111 字節(jié) , 每個(gè)像素點(diǎn)占 4 字節(jié) , 一張寬度 WWW, 高度 HHH 的圖片 , 在內(nèi)存中的大小是 W×H×4W \times H \times 4W×H×4 字節(jié) ;
② RGB_555 像素格式 : Red ( 紅 ) 占 555 位 , Green ( 綠 ) 占 666 位 , Blue ( 藍(lán) ) 占 555 位 , 每個(gè)像素點(diǎn)占 5+6+5=165 + 6 + 5 = 165+6+5=16 位 , 222 字節(jié) , 一張寬度 WWW, 高度 HHH 的圖片 , 在內(nèi)存中的大小是 W×H×2W \times H \times 2W×H×2 字節(jié) ;
Android 中 Bitmap 在內(nèi)存中的大小與圖片大小無(wú)關(guān) , 只與像素格式和像素點(diǎn)個(gè)數(shù)有關(guān) ;
內(nèi)存中的大小只與分辨率有關(guān) , 與磁盤大小無(wú)關(guān) ;
二、Bitmap 內(nèi)存占用計(jì)算示例
1. 獲取 Bitmap 最小字節(jié)數(shù) : 調(diào)用 Bitmap 對(duì)象的 getByteCount 方法 , 可以獲取到 Bitmap 對(duì)象對(duì)應(yīng)圖像在內(nèi)存中占用的最小字節(jié)數(shù) ;
// 從資源文件中加載內(nèi)存 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blog); // 打印 Bitmap 對(duì)象的寬高, 字節(jié)大小 Log.i("Bitmap", bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());2. 打印結(jié)果 : 寬度 5224 像素 , 高度 2678 像素 , 內(nèi)存中大小為 55959488 字節(jié) ;
2020-06-29 20:32:12.794 9675-9675/kim.hsl.bm I/Bitmap: 5224 , 2678 , 559594883. Bitmap 占內(nèi)存大小計(jì)算 : Android 中默認(rèn)使用 ARGB_8888 像素格式 , 每個(gè)像素點(diǎn)占 444 字節(jié) , 上圖寬 5224 , 高 2678;
5224×2678×4=55,959,4885224 \times 2678 \times 4 = 55,959,4885224×2678×4=55,959,488
最終 Bitmap 在內(nèi)存中的大小是 55,959,488 字節(jié) ;
三、Bitmap 內(nèi)存占用與像素密度
1 . BitmapFactory.Options 中封裝了兩個(gè)像素密度相關(guān)的值 :
① inDensity 像素密度值 : 表示該 Bitmap 圖像的像素密度值 ;
/*** Bitmap 圖像的像素密度 ; * Bitmap.setDensity(int) 操作會(huì)導(dǎo)致被返回的圖像會(huì)被強(qiáng)制設(shè)置一個(gè)像素密度值 ; * 假如該設(shè)置的像素密度值 inDensity 與 目標(biāo)像素密度值 inTargetDensity 不同 , * 并且 inScaled 被設(shè)置成 true , 那么該 Bitmap 就會(huì)被縮放到 inTargetDensity 對(duì)應(yīng)的像素密度 ,* 然后再返回 ; * * 如果該值是 0 , 那么就默認(rèn)該像素密度值就是資源文件對(duì)應(yīng)的像素密度值 ;*/ public int inDensity;② inTargetDensity 目標(biāo)像素密度值 : 表示要縮放到的目標(biāo)圖像像素密度值 ;
/*** 將要被繪制的目標(biāo)像素密度值 ;* 該值需要結(jié)合 inScaled 值使用 , 如果同時(shí)設(shè)置了 inScaled = true , 和 inDensity 像素密度值 , * 在圖像返回時(shí) , 會(huì)自動(dòng)將圖像按照 inDensity 向 inTargetDensity 縮放 ; */ public int inTargetDensity;如果 inDensity 小 , inTargetDensity 大 , 圖像會(huì)被放大到原圖像的 inTargetDensity / inDensity 倍 ;
如果 inDensity 大 , inTargetDensity 小 , 圖像會(huì)被縮小到原圖像的 inTargetDensity / inDensity 倍 ;
2 . 設(shè)計(jì)圖片在資源文件中放置規(guī)則 :
① 設(shè)計(jì)稿分辨率 480 x 320 : 圖片放在 mdpi 像素密度下 ; density 1, densityDpi 160 ;
② 設(shè)計(jì)稿分辨率 800 x 480 : 圖片放在 hdpi 像素密度下 ; density 1.5, densityDpi 240;
③ 設(shè)計(jì)稿分辨率 1280 x 720 : 圖片放在 xhdpi 像素密度下 ; density 2, densityDpi 320;
④ 設(shè)計(jì)稿分辨率 1920 x 1080 : 圖片放在 xxhdpi 像素密度下 ; density 3, densityDpi 480;
屏幕密度 density , 屏幕像素密度 densityDpi , 關(guān)系是 density x 160 = densityDpi ;
3 . 獲取當(dāng)前的手機(jī)像素密度值 : 調(diào)用如下代碼 , 獲取當(dāng)前手機(jī)屏幕的像素密度值 ;
getResources().getDisplayMetrics().densityDpi獲取的測(cè)試機(jī)的像素密度是 420 ;
四、Bitmap 內(nèi)存占用與像素密度示例
1 . 不同屏幕密度資源適配 : 原圖 1990 x 1020 ;
將同樣大小的圖片 , 分別拷貝到不同的目錄 , 并命名 , 打印結(jié)果 :
代碼示例 :
package kim.hsl.bm;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; import android.widget.TextView;public class MainActivity extends AppCompatActivity {static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView tv = findViewById(R.id.sample_text);tv.setText(stringFromJNI());Log.i("Bitmap", "getResources().getDisplayMetrics().densityDpi : " +getResources().getDisplayMetrics().densityDpi +" , getResources().getDisplayMetrics().density : " +getResources().getDisplayMetrics().density);// 從資源文件中加載內(nèi)存Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blog);// 打印 Bitmap 對(duì)象的寬高, 字節(jié)大小Log.i("Bitmap", "blog : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_h);// 打印 Bitmap 對(duì)象的寬高, 字節(jié)大小Log.i("Bitmap", "blog_h : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_m);// 打印 Bitmap 對(duì)象的寬高, 字節(jié)大小Log.i("Bitmap", "blog_m : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_x);// 打印 Bitmap 對(duì)象的寬高, 字節(jié)大小Log.i("Bitmap", "blog_x : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_xx);// 打印 Bitmap 對(duì)象的寬高, 字節(jié)大小Log.i("Bitmap", "blog_xx : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_xxx);// 打印 Bitmap 對(duì)象的寬高, 字節(jié)大小Log.i("Bitmap", "blog_xxx : " + bitmap.getWidth() + " , " +bitmap.getHeight() + " , " +bitmap.getByteCount());}public native String stringFromJNI(); }2 . 執(zhí)行結(jié)果 :
2020-06-29 21:32:59.398 12296-12296/kim.hsl.bm I/Bitmap: getResources().getDisplayMetrics().densityDpi : 420 , getResources().getDisplayMetrics().density : 2.625 2020-06-29 21:32:59.551 12296-12296/kim.hsl.bm I/Bitmap: blog : 5224 , 2678 , 55959488 2020-06-29 21:32:59.628 12296-12296/kim.hsl.bm I/Bitmap: blog_h : 3483 , 1785 , 24868620 2020-06-29 21:32:59.775 12296-12296/kim.hsl.bm I/Bitmap: blog_m : 5224 , 2678 , 55959488 2020-06-29 21:32:59.828 12296-12296/kim.hsl.bm I/Bitmap: blog_x : 2612 , 1339 , 13989872 2020-06-29 21:32:59.864 12296-12296/kim.hsl.bm I/Bitmap: blog_xx : 1741 , 893 , 6218852 2020-06-29 21:32:59.894 12296-12296/kim.hsl.bm I/Bitmap: blog_xxx : 1306 , 669 , 34948563 . 結(jié)果分析 :
本測(cè)試機(jī) : 屏幕密度 density = 2.625 , 屏幕像素密度 densityDpi = 420
原圖 1990 x 1020 ;
① 圖片放在 hdpi : 該像素密度對(duì)應(yīng) density = 1.5 , densityDpi = 240 ;
加載到內(nèi)存的寬度=1990×2.6251.5=3,482.5?加載到內(nèi)存的寬度 = 1990 \times \dfrac{2.625}{1.5} = 3,482.5?加載到內(nèi)存的寬度=1990×1.52.625?=3,482.5?
加載到內(nèi)存的高度=1020×2.6251.5=1785加載到內(nèi)存的高度 = 1020\times \dfrac{2.625}{1.5} = 1785加載到內(nèi)存的高度=1020×1.52.625?=1785
② 圖片放在 mdpi : 該像素密度對(duì)應(yīng) density = 1 , densityDpi = 160;
加載到內(nèi)存的寬度=1990×2.6251=5,223.75加載到內(nèi)存的寬度 = 1990 \times \dfrac{2.625}{1} = 5,223.75加載到內(nèi)存的寬度=1990×12.625?=5,223.75
加載到內(nèi)存的高度=1020×2.6251=2,677.5加載到內(nèi)存的高度 = 1020\times \dfrac{2.625}{1} = 2,677.5加載到內(nèi)存的高度=1020×12.625?=2,677.5
③ 圖片放在 xhdpi : 該像素密度對(duì)應(yīng) density = 2 , densityDpi = 320;
加載到內(nèi)存的寬度=1990×2.6252=2,611.875??加載到內(nèi)存的寬度 = 1990 \times \dfrac{2.625}{2} = 2,611.875??加載到內(nèi)存的寬度=1990×22.625?=2,611.875??
加載到內(nèi)存的高度=1020×2.6252=1,338.75加載到內(nèi)存的高度 = 1020\times \dfrac{2.625}{2} = 1,338.75加載到內(nèi)存的高度=1020×22.625?=1,338.75
④ 圖片放在 xxhdpi : 該像素密度對(duì)應(yīng) density = 3 , densityDpi = 480;
加載到內(nèi)存的寬度=1990×2.6253=1,741.25?加載到內(nèi)存的寬度 = 1990 \times \dfrac{2.625}{3} = 1,741.25?加載到內(nèi)存的寬度=1990×32.625?=1,741.25?
加載到內(nèi)存的高度=1020×2.6253=892.5?加載到內(nèi)存的高度 = 1020\times \dfrac{2.625}{3} = 892.5?加載到內(nèi)存的高度=1020×32.625?=892.5?
這樣原像素密度圖片轉(zhuǎn)換成目標(biāo)像素密度圖片后 , 就會(huì)得到日志中打印出來(lái)的值 ;
總結(jié)
以上是生活随笔為你收集整理的【Android 内存优化】Bitmap 内存占用计算 ( Bitmap 图片内存占用分析 | Bitmap 内存占用计算 | Bitmap 不同像素密度间的转换 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Android 内存优化】Androi
- 下一篇: 【Android 内存优化】Bitmap