Bitmap数据存储位置
- 在Android 2.3.3(API10)之前,Bitmap的像素数据存放在Native内存
- Android3.0之后8.0之前,Bitmap的像素数据被改成放在了Dalvik Heap(java堆)中
- Android8.0之后,Bitmap的像素数据回到Native内存中,但是google改进后可以随着java对象的释放而被快速释放(并且新增了图片内存,提高了绘制效率)
为什么会放回native层
存natvie层用的是一个新的hardware的库,估计是为了更好的发挥硬件性能。仿照ios一个应用可以占去可用内存,为了减少资源浪费,bitmap移动到natvie层,减少jvm的oom风险
Bitmap怎么回收
- 2.3.3之前必须手动recycle,官方推荐使用引用计数来判断是否需要recycle这个Bitmap
- 3.0之后更强调Bitmap的复用,如使用LruCache进行缓存、使用inBitmap进行复用,复用之后两个bitmap都会指向同一个对象
被复用的图片要求:
- 需要isMutable为true
- Android4.4之前被复用的宽高必须相同,4.4之后要求被复用的内存大小必须更大
- 4.4之前inSampleSize必须为1,否则不可以复用
如何判断Bitmap的所占内存大小
getByteCount和getAllocationByteCount
正常情况下两者相等,但是如果使用了inBitmap进行复用,getAllocationByteCount表示真实所占内存大小(会去拿native层的数据大小),而getByteCount表示inBitmap所占大小
如何手动计算
height*width*一个像素所占内存*缩放系数(density的比值的平方)
缩放系数是当前系数密度/图片所在文件夹对应的密度
Bitmap压缩
Bitmap.compress
它是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,不会减少图片的像素。进过它压缩的图片文件大小会变小,但是解码成bitmap后占得内存是不变的
BitmapFactory.Options.inSampleSize
设置inSampleSize之后,Bitmap的宽、高都会缩小inSampleSize倍。先通过BitmapFactory.Options.inJustDecodeBounds在不占用内存的情况下获取图片的宽高信息,后设置inSampleSize设置压缩比例,可以真实压缩bitmap所占用内存。inSampleSize比1小的话会被当做1,任何inSampleSize的值会被取接近2的幂值
其它优化
大图小用用采样inSampleSize,小图大用用矩阵
如下图的使用方式,可以在小图的bitmap大小上实现显示更大图片的效果
Matrix matrix = new Matrix();
matrix.postScale(2, 2, 0, 0);
imageView.setImageMatrix(matrix);
imageView.setScaleType(ScaleType.MATRIX);
imageView.setImageBitmap(bitmap);