由于移动设备内存限制的原因,很多时候我们在自己的应用中不得不考虑到性能的问题,如何使用较少的内存空间来尽可能的获得高效的执行效率,是每个开发者必须考虑的,以图片压缩为例,一张图片所占用的内存空间计算公式如下:
所占内存 = 图片长度 x 图片宽度 x 单位像素占用的字节数
图像的位深度与图片的色彩模式有关,以下是所有的色彩模式:
色彩模式 | 单位像素所占字节数 |
---|---|
ALPHA_8 | 1byte |
ARGB_4444 | 2byte |
ARGB_8888(默认) | 4byte |
RGB_565 | 2byte |
系统默认的色彩模式为ARGB_8888,单位像素占用4个字节,以ARGB_8888为例,一张1920x1080的图片加载到内存中大约占用7.91M,对于移动设备来说,7.9M的内存仅仅只为了一张图片而存在是非常奢侈的内存开销。
我们压缩位图所占内存途径,从内存计算公式来看也就2种途径:
- 图片大小压缩
- 位深度压缩
压缩原图的大小或者选用更加节省空间的色彩模式
在进行大小压缩的时候我们要预先知道图片的原来的高宽,如下:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
int height = options.outHeight;
int width = options.outWidth;
在调用decodeFile之前,设置inJustDecodeBounds 为true,这样decodeFile方法不好真正的加载图片到内存,而是只加载图片的高宽等图像参数,这样我们就可以在不耗费内存的情况下获得图片的宽高等信息。
得到图片的宽高之后,我们就能计算图片的缩放值 inSampleSize
例如,缩放值为1,则代表不压缩,为2,则宽高各为原来的1/2,这样图片大小就为原来的1/4
int heightSam = Math.round((float) height/ (float) reqHeight);
int widthSam = Math.round((float) width / (float) reqWidth);
options.inSampleSize = heightSam < widthSam ? heightSam : widthSam;
我们取较小的那个为缩放值
然后,再设置inJustDecodeBounds 为false,这次我们已经设置了缩放值,可以真正的加载图片了
options.inJustDecodeBounds = false;
Bitmap bitmap= BitmapFactory.decodeFile(filePath, options);
在加载之前可以设置图片使用其他的色彩模式,如下:
options.inPreferredConfig = Bitmap.Config.RGB_565;
这样,我们就能根据自己的需求,按比例加载图片预防OOM的发生
这里主要是通过压缩的方式减少图片占用的内存空间,下一章介绍下图片的文件压缩方法,减少图片文件所占用的外存空间,减少上传图片的流量消耗