0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Android端:优化Bitmap内存的几种方法

张康康 2019-07-29 18:27 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

作者 | Video++极链科技移动端Team秦鹏程

整理 | 包包

初识

Bitmap是图像处理的最重要类之一。用它可以获取图像文件信息,进行图像颜色变换、剪切、旋转、缩放等操作,并可以指定格式保存图像文件。

许多 Android 开发者都对 Bitmap 不陌生,其作为显示图片的载体,会经常接触。而在日常开发中对图片的处理通常会用到第三方的开源库:Glide、Fresco、Picasso...,这些已经足够完善的工具不需要让我们考虑处理 Bitmap 的细节,这使得我们对其不是那么熟悉。

Bitmap 实实在在是内存使用的“大客户”。如何更好的使用 Bitmap,减少其对App内存的使用,是 Android 优化方面不可回避的问题,因此,本文从常规的 Bitmap 使用,到 Bitmap 内存计算,最后分析如何更有效的使用 Bitmap。

了解

Bitmap 占用了多大的内存

Bitmap 用来处理位图,每一张图片的每个像素点都会被读取,每个像素点的大小决定了 Bitmap 的内存大小。

所以计算内存大小的公式为:

占用的内存大小 = 像素总数量(宽x高)x 每个像素的字节大小

单个像素的字节大小

单个像素的字节大小由Bitmap的一个可配置的参数Config来决定。Bitmap中,存在一个枚举类Config,定义了Android中支持的Bitmap配置:

dd10223e3e0a41f3ba4e5857adf086e1


Android系统中,默认Bitmap加载图片,使用ARGB_8888模式。

Bitmap 占用内存大小实例

我们准备一张分辨率为 1920x1080,大小为 273KB 的 jpg 图片,放在手机SD 卡中,调用 BitmatFactory.decodeFile() 加载并显示到一个大小为 640x320 的 ImageView 中,占用的内存如下:


从计算内存大小的公式可以得到加载这张图片使用了大约 7m 的内存,即使是手机内存普遍上涨的今天,这样的开销也是法接受的。

在刚才的实例中,我们是将图片放在了手机的外置 SD 卡中,现在,我们将图片分别放到项目工程的 mipmap-xhdpi, mipmap-xxhdpi, mipmap-xxxhdpi 这三个资源目录中,调用 BitmatFactory.decodeResource() 加载到同样的 ImageView 中看看加载的情况:


我们发现,图片放在不同的资源目录中、使用不同的方法加载,占用的内存也会不同,为了探究这其中原理,需要通过观察 Bitmap.decode 的源码,这一过程是有 native 来完成的,所以我们找到 BitmapFactory.cpp#nativeDecode 开始跟踪,省略了其他不相关的代码:

1b627a3bc6b94c8da34fdf0b6a806f5d


上述代码中,最终 bitmap 是通过 canvas 绘制出来,而 canvas 绘制前有 scale 的操作 scale = (float) targetDensity / density; 这一行代码决定,即缩放的倍率和 targetDensity 和 density 相关,而这两个参数都是从传入的 options 中获取到的,再到 Bitmap.Options 中找到相关的参数:

• inDensity:Bitmap 位图自身的密度、分辨率

• inTargetDensity: Bitmap 最终绘制的目标位置的分辨率

其中 inDensity 和图片存放的资源文件的目录有关,同一张图片放置在不同目录下会有不同的值:

a4a77501595a4a0ca17ea7fad53a2faa


通过以上两个实例,我们得出了 decodeResource() 和 decodeFile() 的区别:

•decodeResource 用于读取Res、Raw等资源,得到的是图片的原始尺寸 * 缩放系数(inDensity)

•decodeFile 用于读取SD卡上的图,得到的是图片的原始尺寸

手动设置缩放系数

在 Bitmap.Options 中还有一个为 inScaled 的属性,如果设置为 false,则不进行缩放,如果设置为 true 或者不设置,则根据 inDensity 和 inTargetDensity 计算缩放系数。 如果你不想依赖于这个系统本身的 density,你可以手动设置 inDensity 和 inTargetDensity 来控制缩放系数:

168ca8c69c4b432e92b3f6eac127cc07


压缩方式 inSampleSize & quality

inSampleSize 指的是压缩分辨率,取值必须为 2 的幂(当不为2的幂时,解码器会取与该值最接近的2的幂),例如,当 inSampleSize = 2 时,一张 1920x1080 的图片,将会被缩小为 960x540,相应的它的像素数和内存占用都被缩小为原来的 1/4。

quality 正如字面意思指的是图片品质,在代码中对应的 api 为:

5c6276611390424d8bb176604c582155


CompressFormat 为 Bitmap 中的枚举类,有三个可用值:

• JPEG:表示以 JPEG 压缩算法进行图像压缩,压缩后的格式可以是 “.jpg” 或者 “.jpeg” ,是一种有损压缩。

• PNG:表示以 PNG 压缩算法进行图像压缩,压缩后的格式可以是 “.png” ,是一种无损压缩。

• WEBP:表示以 WebP 压缩算法进行图像压缩,压缩后的格式可以是 “.webp” ,是一种有损压缩,质量相同的情况下,WebP 格式图像的体积要比 JPEG 格式图像小40%。美中不足的是,WebP格式图像的编码时间“比JPEG格式图像长8倍”。

quality 为图片的品质,取值为 0-100,100 代表最高品质,不被压缩。另外,类似 PNG 这种无损格式会忽略 quality 的设置 stream 为图片被压缩后被保存在的输出流。

然而 Bitmap.compress 方法确实可以压缩图片,但压缩的是存储大小,即放到 disk 上的大小。

调试

现在我们通过几个实例,来验证一下以上的结论,首先来看一下两种压缩方式占用内存的影响:

inSampleSize

45aa8fc9b5214936bcaf103256312559


显示结果 :


以上 ImageView 的大小(640x320),用来加载 1920x1080 的图片确实有些浪费,所以经过计算,将原图压缩后发现图片占用内存的大小减少到原图的 1/10,如果原图本身与控件的大小相差不多,这时候还要缩放的话就会影响到图片显示的质量。

降低图片品质

0b74cd8226bd4e15819acd14b12b53dd


显示结果 :


使用降低图片质量的方式压缩图片,可以发现尽管已经降低了 90% 的品质,图片也变得模糊,但其占用的内存与直接加载还是一样的。

改变 Bitmap.Config

我们已经知道, Bitmap 加载图片默认使用的 config 为 ARGB_8888,而且 ALPHA_8 是只有透明度的, 所以我们来看看改为 ARGB_4444 和 RGB_565 所显示的结果,只需要在 decode 的时候传入设置好的 options 参数,所以这里直接给出显示结果:


可以看到将 config 改为 ARGB_4444,所占用的内存与原图一样,而 RGB_565,变得是原图的 1/2,所以结论也不言而喻了,另外 ARGB_4444,已被官方标记为废弃。

总结

在上面,我们将一张 1920x1080 的图片,不做任何处理解析到内存中,将近占用的 7M,想象一下这样的开销发生在一个图片列表中,内存占用将达到非常夸张的地步。从之前Bitmap占用内存的计算公式来看,减少内存主要可以通过以下几种方式:

• 使用低色彩的解析模式,如RGB565,减少单个像素的字节大小。这样大约能减少一半的内存开销。Android 默认是使用 ARGB_8888 配置来处理色彩,占用4字节,改用RGB_565,将只占用2字节,代价是显示的色彩将相对少,适用于对色彩丰富程度要求不高的场景。

• 资源文件合理放置,高分辨率图片可以放到高分辨率目录下。和图片的具体分辨率有关,建议开发中,高分辨率的图像应该放置到合理的资源目录下,注意到Android默认放置的资源目录是对应于160dpi,目前手机屏幕分辨率越来越高,此处能节省下来的开销也是很可观的。理论上,图片放置的资源目录分辨率越高,其占用内存会越小,但是低分辨率图片会因此被拉伸,显示上出现失真。另一方面,高分辨率图片也意味着其占用的本地储存也变大。

• 图片缩小,减少尺寸。理论上根据适用的环境,是可以减少十几倍的内存使用的,它基于这样一个事实:源图片尺寸一般都大于目标需要显示的尺寸,因此可以通过缩放的方式,来减少显示时的图片宽高,从而大大减少占用的内存。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Android
    +关注

    关注

    12

    文章

    4041

    浏览量

    134740
  • BITMAP
    +关注

    关注

    0

    文章

    4

    浏览量

    6665
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    器件工艺协同优化中加速版图设计的三种方法

    器件工艺协同优化(DTCO)流程需要生成海量版图。本文将介绍几种借助自动化手段,加速这一耗时流程的实现方法
    的头像 发表于 03-24 09:41 337次阅读
    器件工艺协同<b class='flag-5'>优化</b>中加速版图设计的三<b class='flag-5'>种方法</b>

    深度解析 | DMA-BUF适配Android与RK特性核心Patch:高性能内存管理升级方案

    support ANDROID and RK feature,通过12个文件的深度改造与重构,为DMA-BUF机制注入了Android生态适配与RK平台专属优化的双重能力,同时完善了其底层
    的头像 发表于 03-16 08:16 3202次阅读
    深度解析 | DMA-BUF适配<b class='flag-5'>Android</b>与RK特性核心Patch:高性能<b class='flag-5'>内存</b>管理升级方案

    知识分享|连接器焊接方法几种

    连接器是一种用于连接电路的元件,通常由金属制成。下面跟小欣一起看看连接器的焊接方法有哪几种呢?烙铁焊接法是最常见的连接器焊接方法之一。使用烙铁将连接器和电路板焊接在一起,这种方法需要使
    的头像 发表于 01-20 17:57 1522次阅读
    知识分享|连接器焊接<b class='flag-5'>方法</b>有<b class='flag-5'>几种</b>?

    rk基于linux/android内存管理

    一、内存分布   U-Boot 由前级 Loader 加载到 CONFIG_SYS_TEXT_BASE 地址,初始化时会探明当前系统的总内存容 量, 32 位平台上认为最大 4GB 可用(但是不影响
    的头像 发表于 12-15 10:42 332次阅读
    rk基于linux/<b class='flag-5'>android</b><b class='flag-5'>内存</b>管理

    Linux Swap交换空间详解:Android编译内存不足?这样扩充立竿见影

        在  Linux  系统使用过程中,你是否遇到过  “ 内存不足 ”  的报错?比如编译  Android  源码时,明明按教程操作,却因物理内存没达到  16G  要求而编译中断?这正是
    的头像 发表于 12-06 08:10 4683次阅读

    有多少种方法可以进行频响曲线测量?

    APx500软件提供了频响曲线的多种测量方法,对一个音频产品的频响特性进行测量分析。如果只用一个测量对一个音频产品进行评价,那这个测量就是频响曲线,APx500软件提供了多种方法可以进行频响曲线测量
    的头像 发表于 11-14 11:29 1319次阅读
    有多少<b class='flag-5'>种方法</b>可以进行频响曲线测量?

    内存与数据处理优化艺术

    内存访问是程序运行的瓶颈之一。减少内存访问次数可以显著提高程序的运行速度。 在C语言中,指针是直接操作内存的利器。使用指针遍历数组不仅代码更简洁,而且效率更高。例如,用指针直接访问内存
    发表于 11-14 07:46

    GPIO位输出操作的几种方法分享

    ;    //端口A的位3输出1   PAout03 = 0;    //端口A的位3输出0 5、综述   以上4种方法,1、2两种较为多见;方法3为位带操作,速度最快,但只对具备位带的U有效;方法4是一种新颖的通用
    发表于 11-13 07:50

    蜂鸟E203内核优化方法

    。 修改内核参数:对蜂鸟E203的内核参数进行相应修改,可以优化内核运行效率,提高系统性能,比如调整缓存大小、内存分配策略等。 资源管理:进行有针对的资源管理,例如调度算法的修改,调整好CPU占用率等,以
    发表于 10-21 07:55

    请问如何优化OpenVINO™工具套件中的内存使用?

    运行OpenVINO™推断时找不到优化内存使用情况的方法
    发表于 06-25 06:56

    ArkUI-X通过Stage模型开发Android应用指南(一)

    Android应用内的Activity的packageName需要与Ability的bundleName一致。 Android应用内的Activity的activityNam
    发表于 06-24 22:16

    鸿蒙5开发宝藏案例分享---内存优化实战指南

    ,里面提供的工具和技巧简直太香了!很多案例和方法,在实际开发中真的能救命,避免应用卡顿、崩溃,还能让设备续航更持久。 今天就来跟大家好好分享这份宝藏,结合官方内容和我的理解,整理成这篇实战性超强的内存优化
    发表于 06-12 17:15

    HarmonyOS优化应用内存占用问题性能优化

    一、使用purgeable优化C++内存 Purgeable Memory是HarmonyOS中native层常用的内存管理机制,可用于图像处理的Bitmap、流媒体应用的一次性数据、
    发表于 05-24 17:20

    HarmonyOS优化应用内存占用问题性能优化

    一、使用生命周期管理优化ArkTS内存 组件的生命周期,指的是组件自身的一些可自执行的方法,这些方法会在特殊的时间点或遇到一些特殊页面行为时被自动触发而执行。 (一)原理介绍 在开发过
    发表于 05-23 15:35

    HarmonyOS优化应用内存占用问题性能优化

    可以避免图片过大或过小导致的显示问题,并提高应用程序的用户体验。 二、多种****方法 在日常开发中,常见的其他减少内存方式有如下几种: 使用虚引用(Weak Reference):在HarmonyOS
    发表于 05-21 11:27