索引
一般来说,图片是Android中的资源使用的重要一块,不论是从流量上还是在内存上,对于图片的优化都是必不可少的,而且Android系统中的OOM也有很多时候是因为图片造成的,所以对于Android系统中图片的优化,可以说是很重要的一部分,而压缩,则是图片优化中必不可少的一步
目录
- 文件压缩
- 内存压缩
1 文件压缩
1 .1质量压缩
质量压缩是一种有损压缩,是Android系统提供的一种常用的图片压缩的API,通过使用Bitmap.compress可以对图片进行质量压缩
//format:压缩的格式
//quality:质量(png格式的图片会忽略此参数)
//stream:输出文件的地址
public boolean compress(CompressFormat format, int quality, OutputStream stream)
1.2 尺寸压缩
通过使用Bitmap.createScaledBitmap可以对图片进行尺寸压缩
//filter:图片滤波处理,true可以让色彩更丰富
Bitmap.createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter)
还有一个方法可以对图片进行剪切
Bitmap.createBitmap (Bitmap source, int x, int y, int width, int height)
1.3 格式压缩
在上述两种压缩方式中,可以通过选择不同的图片格式进行压缩,一般来说,使用jpg有损压缩或webp压缩后文件的大小是小于使用png格式的图片
2 内存压缩
2.1 bitmap内存占用计算
-
ARGB_8888
- ARGB各占8位,即width*height*4
-
RGB_565
- R5位,G6位,B5位,即16位,width*height*2
-
getByteCount
- 可以返回存储此位图像素的大小字节数
-
BitmapFactory.Options
- 控制解码图片参数
- inDensity:表示这个bitmap的像素密度,根据drawable目录
- inTargetDensity:表示要被画出来时的目标(屏幕像素密度)
bitmap在加载一张图片时,会根据inDensity和inTargetDensity这两个值进行缩放
注意:bitmap的大小和文件大小没有关系,只和屏幕的分辨率和显示的大小有关
2.2 bitmap的复用
复用规则
可被复用的Bitmap必须设置inMutable为true;
- Android4.4(API 19)之前只有格式为jpg、png,同等宽高(要求苛刻),inSampleSize为1的Bitmap才可以复用;
- Android4.4(API 19)之前被复用的Bitmap的inPreferredConfig
会覆盖待分配内存的Bitmap设置的inPreferredConfig; - Android4.4(API 19)之后被复用的Bitmap的内存
必须大于等于需要申请内存的Bitmap的内存;
复用代码
/**
* 缩放bitmap
* @param context
* @param id
* @param maxW
* @param maxH
* @return
*/
public static Bitmap resizeBitmap(Context context,int id,int maxW,int maxH,boolean hasAlpha,Bitmap reusable){
Resources resources = context.getResources();
BitmapFactory.Options options = new BitmapFactory.Options();
// 只解码出 outxxx参数 比如 宽、高
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources,id,options);
//根据宽、高进行缩放
int w = options.outWidth;
int h = options.outHeight;
//设置缩放系数
options.inSampleSize = calcuteInSampleSize(w,h,maxW,maxH);
if (!hasAlpha){
options.inPreferredConfig = Bitmap.Config.RGB_565;
}
options.inJustDecodeBounds = false;
// 需要设置为异变的才能够被复用内存
options.inMutable = true;
options.inBitmap = reusable;
return BitmapFactory.decodeResource(resources,id,options);
}
/**
* 计算缩放系数
* @param w
* @param h
* @param maxW
* @param maxH
* @return 缩放的系数
*/
private static int calcuteInSampleSize(int w,int h,int maxW,int maxH) {
int inSampleSize = 1;
if (w > maxW && h > maxH){
inSampleSize = 2;
//循环 使宽、高小于 最大的宽、高
while (w /inSampleSize > maxW && h / inSampleSize > maxH){
inSampleSize *= 2;
}
}
return inSampleSize;
}
2.3 bitmap的内存位置
- android3.0以下,bitmap的内存在native中
- android3.0 ~ android8.0以下,bitmap内存在java中
- android8.0及以上,bitmap内存在native中
对于在native中的bitmap,需要手动调用bitmap.recycle()进行释放内存,不如虚拟机只会回收Java层的内存,并不会回收native中的内存,所以需要维护一个线程回收bitmap,具体写法可以参考glide图片加载框架https://github.com/bumptech/glide/blob/master/library/src/main/java/com/bumptech/glide/load/engine/ActiveResources.java
总结
图片压缩分为文件压缩和内存压缩,一般来说文件压缩在设计师给出图片的时候即可完成,可以通过图片压缩的一些网站进行,内存压缩则需要根据产品具体的需求进行实现,虽然现在一般的图片加载框架中已经做了大部分功能,但是对于图片压缩的具体实现,还是需要有所了解为好
注:此文属作者原创,转载请标明出处
网友评论