由于jvm分配给每个应用的运行内存是有限的,如果加载的图片过大,很有可能回导致oom。 并且在平时的项目中,一般要加载的图片的尺寸远远大于imageview控件的尺寸,如果按照原图显示的话, 会造成资源的浪费。
所以我们在加载图片优化时,通常做的做法就是图片压缩,和图片缓存。
如何计算一个Bitmap占用内存的大小
内存大小 = 宽度像素 x (inTargetDensity / inDensity) x 高度像素 x (inTargetDensity / inDensity)x 一个像素所占的内存
Bitmap 在内存当中占用的大小其实取决于:
-
色彩格式,前面我们已经提到,如果是 ARGB8888 那么就是一个像素4个字节,如果是 RGB565 那就是2个字节
-
原始文件存放的资源目录(是 hdpi 还是 xxhdpi 可不能傻傻分不清楚哈)
-
目标屏幕的密度(所以同等条件下,红米在资源方面消耗的内存肯定是要小于三星S6的)
注:放在drawable目录下的图片可能会进行拉伸,而放在存储空间内的不会进行拉伸。这里inDensity表示目标图片的dpi(放在哪个资源文件夹下),inTargetDensity表示目标屏幕的dpi,所以你可以发现inDensity和inTargetDensity会对Bitmap的宽高进行拉伸,进而改变Bitmap占用内存的大小。
在Bitmap里有两个获取内存占用大小的方法。
getByteCount():API12 加入,代表存储 Bitmap 的像素需要的最少内存。 getAllocationByteCount():API19 加入,代表在内存中为 Bitmap 分配的内存大小,代替了 getByteCount() 方法。 在不复用 Bitmap 时,getByteCount() 和 getAllocationByteCount 返回的结果是一样的。在通过复用 Bitmap 来解码图片时,那么 getByteCount() 表示新解码图片占用内存的大 小,getAllocationByteCount() 表示被复用 Bitmap 真实占用的内存大小(即 mBuffer 的长度)。
图片压缩
1 选择合适的图片格式(bitmap格式)
ALPHA_8 每个像素占用1byte内存
ARGB_4444 每个像素占用2byte内存
ARGB_8888 每个像素占用4byte内存(默认)
RGB_565 每个像素占用2byte内存
2 质量压缩和像素压缩(尺寸压缩)
- 质量压缩: 通过bitmap.compress压缩图片质量,
- 像素压缩:通过BitmapFactory.Options()设置inSampleSize采样率压缩图片大小
3. 图片复用
弱引用和缓存池LurCache和DiskLruCache