当图片,尤其是大图片加载到内存的时候,是非常占用系统内存的,因此需要对图片进行优化处理,对于各种类型的图片,在系统中内存占用也是不同的。
1、Bitmap的内存使用
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.wyz_p);
Log.e("TAG","图片的大小=="+bitmap.getWidth()+"X"+bitmap.getHeight()
+" 图片的内存大小==="+bitmap.getByteCount());
将一张PNG图片加载到内存中,看内存占用
2020-03-26 11:04:19.329 3807-3807/com.example.myapplication E/TAG: 图片的大小==1278X1572 图片的内存大小===8036064
在之前《Android屏幕适配》的时候讲过,一般情况都是以160dpi为基准,属于mdpi的范围,现在的Android手机一般都是400左右的dpi,也就是属于xxhdpi的范围,那么将图片放到对应的dpi文件夹下,图片的内存占用又是什么样的呢?
2020-03-26 13:38:24.272 18041-18041/com.example.myapplication E/TAG: 图片的大小==426X524 图片的内存大小===892896
将图片放到xxhdpi的文件夹下,图片的尺寸有很大变化,内存下降了10倍。
2、图片压缩
现在放在合适的xxhdpi的目录下的时候,当我们使用BitmapFactory
工具加载Bitmap到内存的时候,就是426524的尺寸,也会给图片分配892896内存,但是如果项目中只需要8080的图片大小,怎么处理?
在使用BitmapFactory
调用decodeResource
方法中,其实是通过IO流的方式实现的。
public static Bitmap decodeResource(Resources res, int id, Options opts) {
validate(opts);
Bitmap bm = null;
InputStream is = null;
try {
final TypedValue value = new TypedValue();
is = res.openRawResource(id, value);
//实际就是使用decodeResourceStream方法,来加载图片
bm = decodeResourceStream(res, value, is, null, opts);
} catch (Exception e) {
/* do nothing.
If the exception happened on open, bm will be null.
If it happened on close, bm is still valid.
*/
} finally {
try {
if (is != null) is.close();
} catch (IOException e) {
// Ignore
}
}
if (bm == null && opts != null && opts.inBitmap != null) {
throw new IllegalArgumentException("Problem decoding into existing bitmap");
}
return bm;
}
在decodeResourceStream
方法中,会创建一个Options类,然后判断该类的两个参数,inDensity
代表像素密度,根据Drawable目录进行计算,还有一个参数inTargetDensity
代表画在屏幕上的像素密度,都是通过DisplayMetrics来控制,然后将图片加载到内存。
public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
@Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
validate(opts);
if (opts == null) {
opts = new Options();
}
if (opts.inDensity == 0 && value != null) {
final int density = value.density;
if (density == TypedValue.DENSITY_DEFAULT) {
opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
} else if (density != TypedValue.DENSITY_NONE) {
opts.inDensity = density;
}
}
if (opts.inTargetDensity == 0 && res != null) {
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
}
return decodeStream(is, pad, opts);
}
这个Options
是默认的系统参数,在decodeResource
我们可以自己去手动设置这个参数。
public class ImageResize {
//图片压缩
public static Bitmap resizeBitmap(Context context,int id,int maxW,int maxH,boolean isAlpha){
Resources resources = context.getResources();
//创建Options参数
BitmapFactory.Options options = new BitmapFactory.Options();
//设置Options参数
options.inJustDecodeBounds = true;
//这个时候加载并不会分配内存,而是会得到图片的宽度和高度
BitmapFactory.decodeResource(resources, id, options)