我们已经知道了BitmapFactory是如何通过各种资源创建Bitmap了,那么我们如何合理的使用它呢?以下是几个我们使用Bitmap需要关注的点
-
Size
- 这里我们来算一下,在Android中,如果采用
Config.ARGB_8888的参数去创建一个Bitmap,这是Google推荐的配置色彩参数,也是Android4.4及以上版本默认创建Bitmap的Config参数(Bitmap.Config.inPreferredConfig的默认值),那么每一个像素将会占用4byte,如果一张手机照片的尺寸为1280×720,那么我们可以很容易的计算出这张图片占用的内存大小为 1280x720x4 = 3686400(byte) = 3.5M,一张未经处理的照片就已经3.5M了! 显而易见,在开发当中,这是我们最需要关注的问题,否则分分钟OOM!
- 那么,我们一般是如何处理Size这个重要的因素的呢?,当然是调整
Bitmap的大小到适合的程度啦!辛亏在BitmapFactory中,我们可以很方便的通过BitmapFactory.Options中的options.inSampleSize去设置Bitmap的压缩比,官方给出的说法是
If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory....For example, inSampleSize == 4 returns
an image that is 1/4 the width/height of the original, and 1/16 the
number of pixels. Any value <= 1 is treated the same as 1.
很简洁明了啊!也就是说,只要按计算方法设置了这个参数,就可以完成我们Bitmap的Size调整了。那么,应该怎么调整姿势才比较舒服呢?下面先介绍其中一种通过InputStream的方式去创建Bitmap的方法,上一段从Gallery中获取照片并且将图片Size调整到合适手机尺寸的代码:
static final int PICK_PICS = 9;
public void startGallery(){
Intent i = new Intent();
i.setAction(Intent.ACTION_PICK);
i.setType("image/*");
startActivityForResult(i,PICK_PICS);
}
private int[] getScreenWithAndHeight(){
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
return new int[]{dm.widthPixels,dm.heightPixels};
}
/**
*
* @param actualWidth 图片实际的宽度,也就是options.outWidth
* @param actualHeight 图片实际的高度,也就是options.outHeight
* @param desiredWidth 你希望图片压缩成为的目的宽度
* @param desiredHeight 你希望图片压缩成为的目的高度
* @return
*/
private int findBestSampleSize(int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
double wr = (double) actualWidth / desiredWidth;
double hr = (double) actualHeight / desiredHeight;
double ratio = Math.min(wr, hr);
float n = 1.0f;
//这里我们为什么要寻找 与ratio最接近的2的倍数呢?
//原因就在于API中对于inSimpleSize的注释:最终的inSimpleSize应该为2的倍数,我们应该向上取与压缩比最接近的2的倍数。
while ((n * 2) <= ratio) {
n *= 2;
}
return (int) n;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK){
switch (requestCode){
case PICK_PICS:
Uri uri = data.getData();
InputStream is = null;
try {
is = getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BitmapFactory.Options options = new BitmapFactory.Options();
//当这个参数为true的时候,意味着你可以在解析时候不申请内存的情况下去获取Bitmap的宽和高
//这是调整Bitmap Size一个很重要的参数设置
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream( is,null,options );
int realHeight = options.outHeight;
int realWidth = options.outWidth;
int screenWidth = getScreenWithAndHeight()[0];
int simpleSize = findBestSampleSize(realWidth,realHeight,screenWidth,300);
options.inSampleSize = simpleSize;
//当你希望得到Bitmap实例的时候,不要忘了将这个参数设置为false
options.inJustDecodeBounds = false;
try {
is = getContentResolver().openInputStream(uri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(is,null,options);
iv.setImageBitmap(bitmap);
try {
is.close();
is = null;
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}