探索Bitmap使用姿势

本文深入探讨了Android中Bitmap的内存占用和加载速度问题。通过实验数据揭示了从资源文件、网络或本地创建Bitmap的不同内存占用,分析了Bitmap占用内存的计算公式,并提出了优化策略,包括选择合适的解码格式、按需加载和内存复用。此外,文章还研究了Bitmap的加载速度,对比了从资源文件与流中加载的差异,以及不同解码方式的性能。最后,讨论了新的缓存策略——缓存byte[]代替Bitmap的可能性及其优缺点。
摘要由CSDN通过智能技术生成

转载请注明出处:https://lizhaoxuan.github.io

前言

早些时候对Android下GC调用时机比较好奇,所以写了一些case测试各种情况下Android GC调用时机与现象,感兴趣的话可以跳过去瞅瞅 : 《Android GC机制实践调研》

在这个过程中发现一个让人非常震惊的问题:从资源文件中加载一张110kb的图片创建Bitmap对象,占用的内存高达40MB!
为什么为什么为什么??

于是这篇博客便产生了,我希望可以通过一系列测试case,来了解Bitmap在各种场景下的各种使用姿势将会在内存占用和加载速度两方面都有哪些表现,从而从中探索可能的优化点和最佳实践。

各种场景下创建Bitmap内存占用

从资源文件创建Bitmap

1.不同分辨率的drawable文件夹下加载相同素材,Bitmap的内存占用大小

这里我们准备了一张117.16kb 1200*900的jpg图片放到了res/各种分辨率的drawabe目录下。对他们进行分别加载然后输出各种值进行对比,需要说明一下这里加载的意思可以是:执行bitmapFactory.decodeResource 。 与给ImageView设置Resource 、给布局设置背景等创建创建Bitmap或进行图片显示的操作相同。

看下实验数据

【努比亚Z9 Nubia NX508J】 分辨率1080 * 1920 像素密度:424ppi

文件夹 getByteCount getRowBytes getHeight getWidth
drawable 38880000b ≈ 37mb 14400b 2700 3600
mdip 38880000b ≈ 37mb 14400b 2700 3600
xhdip 9720000b ≈ 9mb 7200b 1350 1800
xxhdip 4320000b ≈ 4mb 4800b 900 1200

38880000b是什么概念?37MB!!
想一下,你的应用还啥都没干呢,就仅是加载了一张图片将近40MB的内存就被占用了,再加上其他一些操作,内存妥妥的就跳到临界值了,如果再有一些不当的溢出,OOM指日可待!

似乎,图片放在分辨率越高的文件夹下,内存占用越小

2.不同格式的图片创建Bitmap内存占用大小

上面测试用的是jpg,而通常我们开发中使用的都是png,看到这么大的内存占用,我有想过是否是因为图片格式的问题,于是把这张图片丢到美图秀秀里(美图秀秀真好用),然后分别导出了长宽一样的jpg和png两张图片,放到资源文件夹中进行加载。

【努比亚Z9  Nubia NX508Jdrawable_jpg_1.jpg 1200*900  135.76kb
drawable_png_1.png 1200*900  1.64mb

jpg getByteCount : 38880000 getRowBytes:14400 getHeight:2700 getWidth:3600
png getByteCount : 38880000 getRowBytes:14400 getHeight:2700 getWidth:3600

内存占用和之前一样,并且虽然png的图片本身高达1.64mb,但内存占用依然只是37mb。

从资源文件中加载图片的内存占用与图片格式、图片占硬盘大小无关!(但和apk包体积有关)

3.不同的分辨率的设备加载同一张素材,Bitmap内存占用大小

Android存在着很多分辨率适配问题,不同drawable文件夹也是为了适配而存在的,所以我们还要挑几个分辨率不一样的手机看一下:

【荣耀畅玩4X】 分辨率:1280 * 720 像素密度:267ppi

文件夹 getByteCount getRowBytes getHeight getWidth
drawable 17280000b ≈ 16mb 9600b 1800 2400
mdip 17280000b ≈ 16mb 9600b 1800 2400
xhdip 4320000b ≈ 4mb 4800b 900 1200
xxhdip 1920000b ≈ 2mb 3200b 600 800

诶?很明显啊,选一个分辨率低一点的手机,果然相同条件的图片加载内存占用是不一样的。我这正好还有一个和努比亚分辨率一样的手机,用这个也测一下:

【乐视 le x620】 分辨率:1080 * 1920 像素密度:401ppi

文件夹 getByteCount getRowBytes getHeight getWidth
drawable 29773800b ≈ 28mb 12600b 2363 3150
mdip 29773800b ≈ 28mb 12600b 2363 3150
xhdip 7440300b ≈ 7mb 6300b 1181 1575
xxhdip 3309600b ≈ 3mb 4200b 788 1050

问题来了,虽然分辨率是一样的,但是内存占用却不同,关键因素不在分辨率,那在什么呢?

我们都知道我们的应用程序在不同的设备上,Android系统会从不同的资源文件夹下获取图片资源,而其选择的本质不是屏幕的长宽比,是像素密度。

所以这里的关键在于像素密度!从资源文件中加载图片的内存占用与像素密度有关!

OK,上面的结论都是通过数据推理出来的一些表象现状。这里先进行一个小总结:

  • 从资源文件中创建Bitmap,图片所在分辨率越高的drawable文件夹,Bitmap占用内存越小。(单从内存的角度可以这样考量,但从实际应用过程中,所有素材都放到分辨率最高的文件夹并不是合适的做法)
  • 从资源文件中创建Bitmap,Bitmap占用内存大小与图片宽高极为有关,与图片本身格式以及占硬盘大小无关。
  • 从资源文件中创建Bitmap,Bitmap占用内存大小与手机像素密度极为有关。

从网络或本地存储创建Bitmap

通过资源文件创建Bitmap,Android系统会为了适配不同屏幕,而对图片进行一些调整,导致不同情况下内存占用区别很大。那么如果是从网络或本地存储中创建的Bitmap也会因为设备的像素密度而有很大差异吗?

我们来实验一下,我从网络下载一张图片,然后观察内存情况。

我选了一张216932b ≈ 212kb 1600 *1280 的jpg图片下载,并创建一个Bitmap

【努比亚Z9  Nubia NX508J 分辨率1080 * 1920  像素密度:424ppi 】
网络下载:
byte[] size : 216932 ≈ 212kb
bitmap size : 8192000 ≈ 7.8125mb
同一张图片放到资源文件中加载:
drawable getByteCount : 73728000 ≈ 70mb getRowBytes:19200 getHeight:3840 getWidth:4800
mdip getByteCount : 73728000 ≈ 70mb getRowBytes:19200 getHeight:3840 getWidth:4800
xhdip getByteCount : 18432000 ≈ 17.5mb getRowBytes:9600 getHeight:1920 getWidth:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值