Moosphan/Android-Daily-Interview

2019-09-10:如何计算一张图片所占的内存空间大小?

Moosphan opened this issue · 4 comments

2019-09-10:如何计算一张图片所占的内存空间大小?

刚查了一下资料,总结如下:
通常情况下图片占用内存的大小:图片分辨率X像素点大小。
api获取方法为bitmap.getByteCount()。
如果放入res/drawable下,通过BitmapFactory.decodeResource()方法加载不同dpi文件下的同一张图片到内存的大小是不一样(存在分辨率的转换),同时也与设备的dpi大小有关。而放在sd卡、网络或者assert里则是一样的(即使是不通dpi的设备)。图片占用内存大小跟控件大小无关(glide是先拿到控件大小,再去对图片加载做的处理)。
图片开源库都基本做了处理,可以查看相关资料。资料来源:https://www.cnblogs.com/dasusu/p/9789389.html。

 图片所占用的Bitmap大小计算方法,根据我们所放置图片的目录不同,所以图片多多少少长度和宽度会有一些变化,这个变化和我们所用的设备屏幕密度有关,因此可以根据图上的表来计算长和宽

原始图片宽度                 实际显示图片宽度
————————     = ————————————
放入目录DensityDpi        当前手机的像素密度

然后根据我们所设置的像素类型ARGB_8888或RGB_888去乘上对应的1px所表示的byte从而得出图片所占用的内存。

图片占用内存大小=图片宽度图片高度图片位深
图片位深: ARGB_8888 32位、ARGB_4444 16位、ARGB_565 16位
例如: 10801920 ,位深为ARGB_8888的图片的内存占用=1080192032位/8=10801920*4字节= 7.9M

一张图片占用的内存大小的计算公式:分辨率 * 像素点大小;但分辨率不一定是原图的分辨率,需要结合一些场景来讨论,像素点大小就几种情况:ARGB_8888(4B)、RGB_565(2B) 等等。
如果不对图片进行优化处理,如压缩、裁剪之类的操作,那么 Android 系统会根据图片的不同来源决定是否需要对原图的分辨率进行转换后再加载进内存。
图片来源是 res 内的不同资源目录时,系统会根据设备当前的 dpi 值以及资源目录所对应的 dpi 值,做一次分辨率转换,规则如下:新分辨率 = 原图横向分辨率 * (设备的 dpi / 目录对应的 dpi ) * 原图纵向分辨率 * (设备的 dpi / 目录对应的 dpi )。
其他图片的来源,如磁盘,文件,流等,均按照原图的分辨率来进行计算图片的内存大小。
jpg、png 只是图片的容器,图片文件本身的大小与它所占用的内存大小没有什么关系。
基于以上理论,以下场景的出现是合理的:
同个 app,在不同 dpi 设备中,同个界面的相同图片所占的内存大小有可能不一样。
同个 app,同一张图片,但图片放于不同的 res 内的资源目录里时,所占的内存大小有可能不一样。
以上场景之所说有可能,是因为,一旦使用某个热门的图片开源库,那么,以上理论基本就不适用了。
因为系统支持对图片进行优化处理,允许先将图片压缩,降低分辨率后再加载进内存,以达到降低占用内存大小的目的
而热门的开源图片库,内部基本都会有一些图片的优化处理操作:
当使用 fresco 时,不管图片来源是哪里,即使是 res,图片占用的内存大小仍旧以原图的分辨率计算。
当使用 Glide 时,如果有设置图片显示的控件,那么会自动按照控件的大小,降低图片的分辨率加载。图片来源是 res 的分辨率转换规则对它也无效。

Android中一张图片占据的内存大小是如何计算