参数作用

  • BitmapFactory.Options这个参数可以设置Bitmap的采样率,通过该比那图片的宽度、高度、缩放比例等,以达到减少图片的像素的目的,设置这个值可以更好的控制、显示和使用Bitmap,可以使用该值降低OOM出现的概率
  • BitmapFactory.Options的常用成员变量(in开头的就是设置参数,out开头的就是获取参数):
public boolean inJustDecodeBounds;
public int inSampleSize;
public int inDensity;
public int inTargetDensity;
public int inScreenDensity;
public boolean inScaled;
public Bitmap.Config inPreferredConfig;
public int outWidth;
public int outHeight;
public String outMimeType;

inJustDecodeBounds

  • 如果将这个参数设置为true, 则表示只解析图片信息,不获取图片,不分配内存,能获取的信息有图片的宽度、高度和图片的MIME类型,分别通过options.outWidth(), options.outHeight(),options.outMimeType返回。
  • 首先将这个参数设置为true
  • 获取图片的宽和高
  • 和显示图片的控件进行比较
  • 如果图片过大就需要压缩
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeResource(getREsources(), R.drawable.XXX, options);
System.out.println(bitmap);
System.out.println(options.outWidth+" " +options.outHeight+" "+options.outMimeType);

结果:
null
XX, XX, XX
  • 上述结果说明:inJustDecodeBounds只会解析Bitmap的高,宽,并不会解析Bitmap对象,整个过程并不占用内存

inSampleSize压缩图片

  • 这个字段表示采样率(采样频率),是指每隔多少个样本采样一次作为结果,比如将这个结果设置为4,意味着从原本图片的4个像素中去一个像素作为返回结果,其余的都被丢弃,这样图片的宽和高就变为原来的1/4,所以采样率越大,图片越小,越失真。
  • 官方建议数值取2的整数次幂,否则系统会自动的向下取整,不可以设置小于1的数值,这样系统会一直使用1来设置采样率
设置采样率
  • 首先我们应该确定控件的大小,然后按照较小的倍数进行缩放,来保证图片不小于控件的大小,这样尽管会多占用内存,但是不至于太失真。
  • 原则:缩放后的图片的尺寸尽量大于等于相应的控件大小
步骤

(1) 获取图片的原始的宽高,通过将Options对象的inJustDecodeBounds属性设置为true后调用decodeResource()函数,实现不真正加载图片(不耗费内存的情况下)获取图片的信息

BitmapFactory.Options options  = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeREsource(getREsource(), resId, options);

(2) 根据据原始宽高和目标宽高计算出inSampleSize

public static int calSampleSize(BitmapFactory.Options options, int dstWidth, int dstHeight){
//原始宽高
int rawWidth = options.outWidth;
int rawHeight = options.outHeight;
if(rawWidth > dstWidth || rawHeight > dstHeight){
//得到图片比目标控件高大的倍数
float ratioHeight = (float) rawheight/dstHeight;
//得到图片比目标控件宽大的倍数
float ratioWidth = (float) rawWidth.dstWidth;
//两者中取最小的以便于覆盖控件不失真
inSampleSize = (int)Math.min(ratioWidth, ratioHeight);
}
return inSampleSize;
}

(3) 根据采样率解析出压缩后的Bitmap

BitmapFactory.Options options2 = new BitmapFactory.Options();
options2.inSampleSize = sampleSize;
try{
Bitmap bmp = BitmapFactory.decodeREsource(getResources(), R.drawable.XXX, options2);
...
}catch(OutOfMemoryError e){
...
}

加载一个完整的Bitmap文件需要占多少空间

文件夹

drawable-ldpi

drawable-mdpi

drawable-hdpi

drawable-xhdpi

drawable-xxhdpi

drawable-xxxhdpi

density

1

1.5

2

3

3.5

4

densityDpi

160

240

320

480

560

640

  • dendity:表示dpi和px的换算比例,1dpi = 1density px
  • densityDpi:表示在对应的分辨率下每英寸有多少个dpi
  • 屏幕上1英寸长 所对应的px数 = 每英寸的dpi数(densityDpi) * dpi所对应的px数(density)
  • 如果屏幕的分辨率和这些文件所在文件夹的分辨率不同时:
  • 缩放比例 = 屏幕分辨率/文件所在文件夹的分辨率
  • 但是在SD卡中的图片,Android的处理策略是不进行缩放
  • Bitmap大小的计算:
  • 默认存储的格式是ARGB_8888每个像素占8位4字节,所以使用宽*高 *4B即可

inScaled

  • 该参数表示是否对当前Bitmap图像进行缩放,如果设置为false表示不进行缩放,如果设置为true或者不设置表示默认的进行动态缩放,默认设置为true
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.niuniuya);
System.out.println(bitmap.getWidth()+" "+bitmap.getHeight()+" "+bitmap.getByteCount());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.niuniuya, options);
System.out.println(bmp.getWidth()+" "+bmp.getHeight()+" "+bitmap.getByteCount());


结果
1200 1200 5760000
400 400 640000

inDensity, inTargetDensity, inScreenDensity

  • inDensity:用于设置文件所在资源文件夹的屏幕分辨率
  • inTargetDensity:表示真实显示的屏幕分辨率
  • inScreenDensity:源码中并没有用到,实际上根本没什么用处
  • scale(缩放比)= inTargetDensity/inDensity
  • 所参数的作用就是通过手动的方式设置资源文件夹的分辨率和真实显示的屏幕分辨率来指定屏幕的缩放比例
options.inScaled = true;
options.inDensity = 1;
options.inTargetDensity = 2;
Bitmap bmp1 = BitmapFactory.decodeResource(getResources(), R.drawable.niuniuya, options);
System.out.println(bmp.getWidth()+" "+bmp.getHeight()+" "+bmp.getByteCount());

结果:
400 400 640000
800 800 2560000

inPreferredConfig

  • 这个参数是用来设置参数格式的,默认使用ARGB_8888, 还有RGB_565, ALPHA_8, ARGB_4444
options.inScaled = true;
options.inDensity = 1;
options.inTargetDensity = 2;
Bitmap bmp1 = BitmapFactory.decodeResource(getResources(), R.drawable.niuniuya, options);
System.out.println(bmp1.getWidth()+" "+bmp1.getHeight()+" "+bmp1.getByteCount());
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bmp2 = BitmapFactory.decodeResource(getResources(), R.drawable.niuniuya, options);
System.out.println(bmp2.getWidth()+" "+bmp2.getHeight()+" "+bmp2.getByteCount());



结果:
宽和高是不会变的
800 800 2560000
800 800 1280000