一、Bitmap 內存佔用
在 Android 中 Bitmap 對象在內存中存儲的的像素格式有兩種 : ARGB_8888 和 RGB_555 ;
① ARGB_8888 像素格式 : Alpha ( 透明度 ) , Red ( 紅 ) , Green ( 綠 ) , Blue ( 藍 ) , 各佔 字節 , 每個像素點佔 4 字節 , 一張寬度 , 高度 的圖片 , 在內存中的大小是 字節 ;
② RGB_555 像素格式 : Red ( 紅 ) 佔 位 , Green ( 綠 ) 佔 位 , Blue ( 藍 ) 佔 位 , 每個像素點佔 位 , 字節 , 一張寬度 , 高度 的圖片 , 在內存中的大小是 字節 ;
Android 中 Bitmap 在內存中的大小與圖片大小無關 , 只與像素格式和像素點個數有關 ;
內存中的大小隻與分辨率有關 , 與磁盤大小無關 ;
二、Bitmap 內存佔用計算示例
1. 獲取 Bitmap 最小字節數 : 調用 Bitmap 對象的 getByteCount 方法 , 可以獲取到 Bitmap 對象對應圖像在內存中佔用的最小字節數 ;
// 從資源文件中加載內存
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blog);
// 打印 Bitmap 對象的寬高, 字節大小
Log.i("Bitmap", bitmap.getWidth() + " , " +
bitmap.getHeight() + " , " +
bitmap.getByteCount());
2. 打印結果 : 寬度 5224 像素 , 高度 2678 像素 , 內存中大小爲 55959488 字節 ;
2020-06-29 20:32:12.794 9675-9675/kim.hsl.bm I/Bitmap: 5224 , 2678 , 55959488
3. Bitmap 佔內存大小計算 : Android 中默認使用 ARGB_8888 像素格式 , 每個像素點佔 字節 , 上圖寬 5224 , 高 2678;
最終 Bitmap 在內存中的大小是 55,959,488 字節 ;
三、Bitmap 內存佔用與像素密度
1 . BitmapFactory.Options 中封裝了兩個像素密度相關的值 :
① inDensity 像素密度值 : 表示該 Bitmap 圖像的像素密度值 ;
/**
* Bitmap 圖像的像素密度 ;
* Bitmap.setDensity(int) 操作會導致被返回的圖像會被強制設置一個像素密度值 ;
* 假如該設置的像素密度值 inDensity 與 目標像素密度值 inTargetDensity 不同 ,
* 並且 inScaled 被設置成 true , 那麼該 Bitmap 就會被縮放到 inTargetDensity 對應的像素密度 ,
* 然後再返回 ;
*
* 如果該值是 0 , 那麼就默認該像素密度值就是資源文件對應的像素密度值 ;
*/
public int inDensity;
② inTargetDensity 目標像素密度值 : 表示要縮放到的目標圖像像素密度值 ;
/**
* 將要被繪製的目標像素密度值 ;
* 該值需要結合 inScaled 值使用 , 如果同時設置了 inScaled = true , 和 inDensity 像素密度值 ,
* 在圖像返回時 , 會自動將圖像按照 inDensity 向 inTargetDensity 縮放 ;
*/
public int inTargetDensity;
如果 inDensity 小 , inTargetDensity 大 , 圖像會被放大到原圖像的 inTargetDensity / inDensity 倍 ;
如果 inDensity 大 , inTargetDensity 小 , 圖像會被縮小到原圖像的 inTargetDensity / inDensity 倍 ;
2 . 設計圖片在資源文件中放置規則 :
① 設計稿分辨率 480 x 320 : 圖片放在 mdpi 像素密度下 ; density 1, densityDpi 160 ;
② 設計稿分辨率 800 x 480 : 圖片放在 hdpi 像素密度下 ; density 1.5, densityDpi 240;
③ 設計稿分辨率 1280 x 720 : 圖片放在 xhdpi 像素密度下 ; density 2, densityDpi 320;
④ 設計稿分辨率 1920 x 1080 : 圖片放在 xxhdpi 像素密度下 ; density 3, densityDpi 480;
屏幕密度 density , 屏幕像素密度 densityDpi , 關係是 density x 160 = densityDpi ;
3 . 獲取當前的手機像素密度值 : 調用如下代碼 , 獲取當前手機屏幕的像素密度值 ;
getResources().getDisplayMetrics().densityDpi
獲取的測試機的像素密度是 420 ;
四、Bitmap 內存佔用與像素密度示例
1 . 不同屏幕密度資源適配 : 原圖 1990 x 1020 ;
將同樣大小的圖片 , 分別拷貝到不同的目錄 , 並命名 , 打印結果 :
代碼示例 :
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");
}
@Override
protected 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);
// 從資源文件中加載內存
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blog);
// 打印 Bitmap 對象的寬高, 字節大小
Log.i("Bitmap", "blog : " + bitmap.getWidth() + " , " +
bitmap.getHeight() + " , " +
bitmap.getByteCount());
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_h);
// 打印 Bitmap 對象的寬高, 字節大小
Log.i("Bitmap", "blog_h : " + bitmap.getWidth() + " , " +
bitmap.getHeight() + " , " +
bitmap.getByteCount());
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_m);
// 打印 Bitmap 對象的寬高, 字節大小
Log.i("Bitmap", "blog_m : " + bitmap.getWidth() + " , " +
bitmap.getHeight() + " , " +
bitmap.getByteCount());
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_x);
// 打印 Bitmap 對象的寬高, 字節大小
Log.i("Bitmap", "blog_x : " + bitmap.getWidth() + " , " +
bitmap.getHeight() + " , " +
bitmap.getByteCount());
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_xx);
// 打印 Bitmap 對象的寬高, 字節大小
Log.i("Bitmap", "blog_xx : " + bitmap.getWidth() + " , " +
bitmap.getHeight() + " , " +
bitmap.getByteCount());
bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.blog_xxx);
// 打印 Bitmap 對象的寬高, 字節大小
Log.i("Bitmap", "blog_xxx : " + bitmap.getWidth() + " , " +
bitmap.getHeight() + " , " +
bitmap.getByteCount());
}
public native String stringFromJNI();
}
2 . 執行結果 :
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 , 3494856
3 . 結果分析 :
本測試機 : 屏幕密度 density = 2.625 , 屏幕像素密度 densityDpi = 420
原圖 1990 x 1020 ;
① 圖片放在 hdpi : 該像素密度對應 density = 1.5 , densityDpi = 240 ;
② 圖片放在 mdpi : 該像素密度對應 density = 1 , densityDpi = 160;
③ 圖片放在 xhdpi : 該像素密度對應 density = 2 , densityDpi = 320;
④ 圖片放在 xxhdpi : 該像素密度對應 density = 3 , densityDpi = 480;
這樣原像素密度圖片轉換成目標像素密度圖片後 , 就會得到日誌中打印出來的值 ;