【Android 内存优化】Bitmap 内存占用计算 ( Bitmap 图片内存占用分析 | Bitmap 内存占用计算 | Bitmap 不同像素密度间的转换 )

简介: 【Android 内存优化】Bitmap 内存占用计算 ( Bitmap 图片内存占用分析 | Bitmap 内存占用计算 | Bitmap 不同像素密度间的转换 )

文章目录

一、Bitmap 内存占用

二、Bitmap 内存占用计算示例

三、Bitmap 内存占用与像素密度

四、Bitmap 内存占用与像素密度示例





一、Bitmap 内存占用


在 Android 中 Bitmap 对象在内存中存储的的像素格式有两种 : ARGB_8888 和 RGB_555 ;



① ARGB_8888 像素格式 : Alpha ( 透明度 ) , Red ( 红 ) , Green ( 绿 ) , Blue ( 蓝 ) , 各占 1 11 字节 , 每个像素点占 4 字节 , 一张宽度 W WW, 高度 H HH 的图片 , 在内存中的大小是 W × H × 4 W \times H \times 4W×H×4 字节 ;


② RGB_555 像素格式 : Red ( 红 ) 占 5 55 位 , Green ( 绿 ) 占 6 66 位 , Blue ( 蓝 ) 占 5 55 位 , 每个像素点占 5 + 6 + 5 = 16 5 + 6 + 5 = 165+6+5=16 位 , 2 22 字节 , 一张宽度 W WW, 高度 H HH 的图片 , 在内存中的大小是 W × H × 2 W \times H \times 2W×H×2 字节 ;



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 像素格式 , 每个像素点占 4 44 字节 , 上图宽 5224 , 高 2678;


5224 × 2678 × 4 = 55 , 959 , 488 5224 \times 2678 \times 4 = 55,959,488

5224×2678×4=55,959,488


最终 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 ;


加 载 到 内 存 的 宽 度 = 1990 × 2.625 1.5 = 3 , 482.5 ‬ 加载到内存的宽度 = 1990 \times \dfrac{2.625}{1.5} = 3,482.5‬加载到内存的宽度=1990×

1.5

2.625


=3,482.5‬


加 载 到 内 存 的 高 度 = 1020 × 2.625 1.5 = 1785 加载到内存的高度 = 1020\times \dfrac{2.625}{1.5} = 1785加载到内存的高度=1020×

1.5

2.625


=1785



② 图片放在 mdpi : 该像素密度对应 density = 1 , densityDpi = 160;


加 载 到 内 存 的 宽 度 = 1990 × 2.625 1 = 5 , 223.75 加载到内存的宽度 = 1990 \times \dfrac{2.625}{1} = 5,223.75加载到内存的宽度=1990×

1

2.625


=5,223.75


加 载 到 内 存 的 高 度 = 1020 × 2.625 1 = 2 , 677.5 加载到内存的高度 = 1020\times \dfrac{2.625}{1} = 2,677.5加载到内存的高度=1020×

1

2.625


=2,677.5



③ 图片放在 xhdpi : 该像素密度对应 density = 2 , densityDpi = 320;


加 载 到 内 存 的 宽 度 = 1990 × 2.625 2 = 2 , 611.875 ‬ ‬ 加载到内存的宽度 = 1990 \times \dfrac{2.625}{2} = 2,611.875‬‬加载到内存的宽度=1990×

2

2.625


=2,611.875‬‬


加 载 到 内 存 的 高 度 = 1020 × 2.625 2 = 1 , 338.75 加载到内存的高度 = 1020\times \dfrac{2.625}{2} = 1,338.75加载到内存的高度=1020×

2

2.625


=1,338.75



④ 图片放在 xxhdpi : 该像素密度对应 density = 3 , densityDpi = 480;


加 载 到 内 存 的 宽 度 = 1990 × 2.625 3 = 1 , 741.25 ‬ 加载到内存的宽度 = 1990 \times \dfrac{2.625}{3} = 1,741.25‬加载到内存的宽度=1990×

3

2.625


=1,741.25‬


加 载 到 内 存 的 高 度 = 1020 × 2.625 3 = 892.5 ‬ 加载到内存的高度 = 1020\times \dfrac{2.625}{3} = 892.5‬加载到内存的高度=1020×

3

2.625


=892.5‬



这样原像素密度图片转换成目标像素密度图片后 , 就会得到日志中打印出来的值 ;


目录
相关文章
|
7月前
|
存储 分布式计算 监控
阿里云服务器实例经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i详解与选择策略
在阿里云现在的活动中,可选的云服务器实例规格主要有经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i实例,虽然阿里云在活动中提供了多种不同规格的云服务器实例,以满足不同用户和应用场景的需求。但是有的用户并不清楚他们的性能如何,应该如何选择。本文将详细介绍阿里云服务器中的经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i实例的性能、适用场景及选择参考,帮助用户根据自身需求做出更加精准的选择。
|
2月前
|
存储 机器学习/深度学习 缓存
阿里云九代云服务器怎么样?计算型c9i、通用型g9i、内存型r9i实例介绍
阿里云第9代云服务器主要实例规格包括计算型c9i、通用型g9i、内存型r9i,本文将为大家介绍阿里云九代云服务器中的计算型c9i、通用型g9i、内存型r9i实例的主要性能特点,并分享最新的活动价格信息,以供参考。
258 1
|
5月前
|
XML Android开发 数据格式
Android利用selector(选择器)实现图片动态点击效果
本文介绍了Android中ImageView的`src`与`background`属性的区别及应用,重点讲解如何通过设置背景选择器实现图片点击动态效果。`src`用于显示原图大小,不拉伸;`background`可随组件尺寸拉伸。通过创建`selector_setting.xml`,结合`setting_press.xml`和`setting_normal.xml`定义按下和正常状态的背景样式,提升用户体验。示例代码展示了具体实现步骤,包括XML配置和形状定义。
249 3
Android利用selector(选择器)实现图片动态点击效果
|
5月前
|
Java Android开发
Android图片的手动放大缩小
本文介绍了通过缩放因子实现图片放大缩小的功能,效果如动图所示。关键步骤包括:1) 在布局文件中设置 `android:scaleType="matrix"`;2) 实例化控件并用 `ScaleGestureDetector` 处理缩放手势;3) 使用 `Matrix` 对图片进行缩放处理。为避免内存崩溃,可在全局配置添加 `android:largeHeap="true"`。代码中定义了 `beforeScale` 和 `nowScale` 变量控制缩放范围,确保流畅体验。
172 8
|
5月前
|
缓存 编解码 Android开发
Android内存优化之图片优化
本文主要探讨Android开发中的图片优化问题,包括图片优化的重要性、OOM错误的成因及解决方法、Android支持的图片格式及其特点。同时介绍了图片储存优化的三种方式:尺寸优化、质量压缩和内存重用,并详细讲解了相关的实现方法与属性。此外,还分析了图片加载优化策略,如异步加载、缓存机制、懒加载等,并结合多级缓存流程提升性能。最后对比了几大主流图片加载框架(Universal ImageLoader、Picasso、Glide、Fresco)的特点与适用场景,重点推荐Fresco在处理大图、动图时的优异表现。这些内容为开发者提供了全面的图片优化解决方案。
192 1
|
7月前
|
存储 编解码 安全
阿里云高性能企业级甄选Intel第八代计算型c8i、通用型g8i和内存型r8i实例简介
计算型c8i、通用型g8i和内存型r8i实例是阿里云推出的高性能企业级甄选Intel第八代云服务器实例,采用CIPU+飞天技术架构,搭载最新的Intel 第五代至强可扩展处理器(代号EMR),性能进一步大幅提升,同时拥有AMX加持的AI能力增强,并在全球范围率先支持TDX机密虚拟机能力,实现了AI增强和全面安全防护的两大特色优势。本文将为您介绍这三个实例规格的性能、适用场景及最新活动价格以及选择指南,以供选择参考。
281 18
|
8月前
|
存储 缓存 安全
阿里云服务器计算型c7/c8y/c8i,通用型g7/g8y/g8i,内存型r7/r8y/r8i区别及选择参考
为了满足不同企业级用户的多样化需求,阿里云在当下的活动中推出了多款计算型、通用型和内存型的云服务器实例,包括计算型c7/c8y/c8i、通用型g7/g8y/g8i以及内存型r7/r8y/r8i等。这些实例各具特色,适用于不同的应用场景和业务需求。本文将为您详细解析这些实例的区别,以及选择参考,帮助您根据自己的需求选择合适的阿里云服务器实例。
|
11月前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
507 21
|
10月前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
198 8

热门文章

最新文章