在android开发过程中图片的存储优化是非常常见,处理不好,时常会造成图片OOM。接下来分享一下我在开发过程中做的相应的处理,仅供各位参考,如有不足还请多多指教。
首先我们知道图片在app存在形式无非就是:file、stream流、bitmap!
一、接下来列出几个图片OOM的出现情况
1、在一个页面中一次性加载过多的图片
2、加载的图片过大
3、bitmap的错误使用
二、图片优化的处理方式:尺寸压缩、质量压缩、内存复用
在此我们先知道一张图片的大小=图片的宽x图片的高x一个像素所占的大小。
1、尺寸压缩
按照一定的比例减小图片的宽高从而减少单位尺寸的像素值,这样的话可以改变图片在内存中的大小。这种做法只是改变了图片在加载时内存中的大小,但是磁盘中图片的大小是没有发生变化的。
代码示例:
/**
* @param pathUrl 文件路径
* @return
*/
public Bitmap getBitmap(String pathUrl) {
// 配置压缩的参数
BitmapFactory.Options options = new BitmapFactory.Options();
// 开始读入图片,此时把options.inJustDecodeBounds 设为true,方便图片在不加载进内存的情况下获取图片的宽高
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(pathUrl, options);//这个时候decode的bitmap为null
options.inJustDecodeBounds = false;//将inJustDecodeBounds设置为false,加载图片数据
//nSampleSize的作用就是可以把图片的宽和高缩小inSampleSize倍,所占内存缩小inSampleSize的平方
//例如,inSampleSize = 2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。
options.inSampleSize = calculateInSampleSize(options,400,100);
bitmap = BitmapFactory.decodeFile(pathUrl, options);//重新读出图片
return bitmap;
}/**
* @param options
* @param reqWidth 我们期望的图片的宽,单位px
* @param reqHeight 我们期望的图片的高,单位px
* @return
*/
public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;//图片的原高
final int width = options.outWidth;//图片的原宽
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}1、质量压缩
质量压缩不会减少图片的像素,它是在保持像素的前提下改变图片的位深及透明度,来达到压缩图片的目的,图片的长,宽,像素都不会改变,它只是改变磁盘中的文件大小,并不能改变加载时内存中的图片大小。
代码示例:
/**
* @param bitmap bitmap
* @param int quality
* @return
*/
public Bitmap qualityBitmap(Bitmap bitmap, int quality){
//quality,可以调节你压缩的比例,但是质量压缩对png格式这种图片没有作用,因为png是无损压缩。
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.WEBP,100,outputStream);
while (outputStream.toByteArray().length/1024>quality){
outputStream.reset();
bitmap.compress(Bitmap.CompressFormat.WEBP,quality,outputStream);
if (quality>5)quality-=5;
else break;
}
ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig=Bitmap.Config.RGB_565;
Bitmap bitmap1 = BitmapFactory.decodeStream(inputStream, null, options);
return bitmap1;
}3、内存复用inbitmap注意点
2.3上,bitmap的数据是存储在native的内存区域,并不是在Dalvik的内存堆上。
3.0开始,系统在BitmapFactory.Options里引入了inBitmap机制来配合缓存机制。如果在载入图片时传入了inBitmap那么载入的图片就是inBitmap里的值。这样可以统一有缓存和无缓存的载入方式。
使用inBitmap,在4.4之前,只能重用相同大小的bitmap的内存区域,而4.4之后你可以重用任何bitmap的内存区域,只要这块内存比将要分配内存的bitmap大就可以。
新申请的bitmap与旧的bitmap必须有相同的解码格式
使用此方法需要inMutable=true,inSampleSize=1
*例外,bitmap也可以通过缩放法压缩(martix)、createScaledBitmap。
以上是别人在项目过程中对图片处理一些做法,写的不错,请多多指教
















