android计算bitmap内存及内存优化

本文详细解析了BitmapFactory中图片加载的内存优化策略,包括inSampleSize的设置、不同配置下每像素大小的影响,以及根据设备dpi调整图片尺寸的方法。通过实例展示了如何减少内存消耗,适用于Android开发人员。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:
https://www.cnblogs.com/dasusu/p/9789389.html
http://www.cocoachina.com/articles/30884

计算公式:

1、如果设置了inSampleSize=1,2,4,8 , 则相应的
Sample高度 = 原图高度 * 1,1/2, 1/4, 1/8;
Sample宽度 = 原图宽度 * 1,1/2, 1/4, 1/8;

2、(BitmapFactory 中 decodeResource() 方法内部会根据 dpi 进行分辨率的转换,其他 decodeXXX() 就没有了,所以,如果不是decodeResource() 或 图片的来源,如磁盘(assets, raw),文件,流等, 则跳过这步
新图的高度 = Sample高度 * (设备的 dpi / 目录对应的 dpi )
新图的宽度 = Sample宽度 * (设备的 dpi / 目录对应的 dpi )

3、
bitmap内存 = 新图的高度 * 新图的宽度 * 每像素大小

参数看下面:
每像素大小根据options中的:
Bitmap.Config.ARGB_8888 : 8bit + 8bit + 8bit + 8bit = 32bit = 4Byte
Bitmap.Config.ARGB_4444 : 4bit + 4bit + 4bit + 4bit = 16bit = 2Byte
Bitmap.Config.RGB_565 : 5bit + 6bit + 5bit = 16bit = 2Byte

原图宽高:
在这里插入图片描述
6个目录对应dip:
L DPI ( Low Density Screen,120 DPI ),0.75
M DPI ( Medium Density Screen, 160 DPI ),1
H DPI ( High Density Screen, 240 DPI ),1.5
XH DPI ( Extra-high density screen, 320 DPI ),2
XXH DPI( xx-high density screen, 480 DPI ),3
XXXH DPI( xxx-high density screen, 640 DPI ),4

   @Override
    public void draw(@NonNull Canvas canvas) {
        try {
            if (mResources != null && mParentViewHeight != 0 && mParentViewWidth != 0) {
                if (mLastBitmap == null) {
                    mLastBitmap = Bitmap.createBitmap(mParentViewWidth, mParentViewHeight, Bitmap.Config.ARGB_4444);
                }

                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeResource(mResources, RES_IDS[curFrame], options);

                options.inScaled = true;
                options.inDensity = mInDensity;
                options.inTargetDensity = mInTargetDensity;
                options.inJustDecodeBounds = false;
                options.inMutable = true;
                options.inSampleSize = 4;
                options.inBitmap = mLastBitmap;  //bitmap内存复用

                Bitmap bitmap = BitmapFactory.decodeResource(mResources, RES_IDS[curFrame], options);

                int canvasWidth = canvas.getWidth();
                int bitMapHeight = bitmap.getHeight();
                int bitMapWidth = bitmap.getWidth();

                canvas.drawBitmap(bitmap, bitMapWidth,bitMapHeight, mPaint);
                 
                Log.e("chen", "density : " +  mResources.getDisplayMetrics().density);
                Log.e("chen", "byteCount : " + bitmap.getByteCount() + "  AllocationByteCount : " + bitmap.getAllocationByteCount());
}

bitmap.getByteCount() :bitmap使用内存的理论值。
bitmap.getAllocationByteCount() :使用options.inBitmap时,bitmap实际使用的内存。

内存优化:
1、设置inSampleSize
2、不影响用户体验的情况下:Bitmap.Config.ARGB_4444

举例:
1、
在这里插入图片描述
2、
在这里插入图片描述

在 Android 中,计算 Drawable(尤其是 Bitmap)的内存占用大小需要根据 图片的像素数据色彩格式 以及 内存管理机制 进行计算。以下是详细的计算方法和关键因素:


1. Bitmap 内存占用计算公式

Bitmap 的内存大小主要由以下因素决定:

  • 宽度(Width):像素宽度(px)
  • 高度(Height):像素高度(px)
  • 色彩格式(Color Format):每个像素占用的字节数

公式

内存大小 (Bytes) = 宽度 × 高度 × 每个像素的字节数

常见色彩格式的像素字节数

色彩格式(Bitmap.Config每个像素占用字节数说明
ALPHA_81 byte仅透明度(无颜色)
RGB_5652 bytes5位红 + 6位绿 + 5位蓝(无透明度)
ARGB_4444 (已废弃)2 bytes4位 Alpha + 4位 R/G/B
ARGB_8888(默认)4 bytes8位 Alpha + 8位 R/G/B
RGBA_F16 (Android 8.0+)8 bytes16位浮点色彩(广色域支持)

示例计算

假设一张 1000×1000 的图片:

  • ARGB_8888(默认)
    1000 × 1000 × 4 = 4,000,000 bytes ≈ 3.81 MB
    
  • RGB_565(节省内存)
    1000 × 1000 × 2 = 2,000,000 bytes ≈ 1.91 MB
    

2. 考虑 Bitmap 的缩放(Density 和 Target Density)

Android 会根据 设备屏幕密度(dpi)资源目录(drawable-xxhdpi 等) 自动缩放 Bitmap,影响最终内存占用。

缩放计算公式

实际内存大小 = (原始宽度 × 缩放比例) × (原始高度 × 缩放比例) × 每像素字节数

其中:

缩放比例 = 设备屏幕密度(dpi) / 资源目录密度(dpi)

常见资源目录密度

资源目录密度(dpi)
drawable-ldpi120
drawable-mdpi160
drawable-hdpi240
drawable-xhdpi320
drawable-xxhdpi480
drawable-xxxhdpi640

示例

假设:

  • 图片放在 drawable-xxhdpi(480 dpi)
  • 设备屏幕密度为 320 dpi(xhdpi)
  • 图片原始尺寸 1000×1000,格式 ARGB_8888

计算:

缩放比例 = 320 / 480 ≈ 0.6667
实际内存大小 = (1000 × 0.6667) × (1000 × 0.6667) × 4 ≈ 666 × 666 × 4 ≈ 1,777,824 bytes ≈ 1.7 MB

结论:比原始内存(4MB)小,因为系统自动缩小了 Bitmap。


3. 获取 Bitmap 内存占用的代码实现

方法 1:直接计算

Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
long memorySize = bitmap.getByteCount(); // 直接返回内存大小(Bytes)
Log.d("BitmapMemory", "Memory: " + memorySize / (1024 * 1024) + " MB");

方法 2:手动计算(适用于 API < 12)

int bytesPerPixel;
switch (bitmap.getConfig()) {
    case ALPHA_8:
        bytesPerPixel = 1;
        break;
    case RGB_565:
    case ARGB_4444:
        bytesPerPixel = 2;
        break;
    case ARGB_8888:
    default:
        bytesPerPixel = 4;
        break;
}
long memorySize = (long) bitmap.getWidth() * bitmap.getHeight() * bytesPerPixel;

4. 优化 Bitmap 内存占用

(1)使用 inSampleSize 进行压缩

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2; // 缩小 2 倍(宽度/高度各减半)
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);

计算方式

内存大小 = (原始宽度 / inSampleSize) × (原始高度 / inSampleSize) × 每像素字节数

(2)使用 RGB_565 替代 ARGB_8888

BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565; // 减少内存占用
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);

(3)及时回收 Bitmap

if (bitmap != null && !bitmap.isRecycled()) {
    bitmap.recycle(); // 释放 Native 内存
    bitmap = null;
}

5. 总结

影响因素说明
宽度 × 高度像素尺寸越大,内存占用越高
色彩格式ARGB_8888(4B) > RGB_565(2B)
屏幕密度缩放低密度设备加载高密度图片会缩小,减少内存
inSampleSize采样压缩可大幅降低内存
Bitmap 复用使用 BitmapFactory.Options.inBitmap 复用内存

最终建议

  • 尽量使用 RGB_565inSampleSize 压缩大图。
  • 使用 GlidePicasso 等库自动优化 Bitmap 内存管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值