由于如今的高清图片占用内存大,而java
Android对单个应用所施加的内存限制,只有十几M,如16M,这致使加载Bitmap的时候很容易出现内存溢出。android
以下报错信息:数组
java.lang.OutOfMemoryError:bitmap size exceeds VM budget
bash
为了解决这个问题,就出现了Bitmap的高效加载策略。性能
其核心思想很简单。 假设经过ImageView来显示图片,不少时候ImageView并无原始图片的尺寸那么大,这个时候把整个图片加载进来后再设置给ImageView,显然是没有必要的,由于ImageView根本没办法显示原始图片,这时候能够按必定的采样率来缩小图片再加载进来,这样图片既能在ImageVIew显示出来,也能下降内存占用从而必定程度上避免OOM,提升Bitmap加载时的性能。ui
BItmap在android中指的是一张图片,经过BitmapFactory类提供的四类方法:spa
decodeFile、decodeResource、decodeStream和decodeByteArray
,分别从文件系统、资源、输入流和字节数组中加载一个Bitmap对象,其中decodeFile和decodeResource又间接调用decodeStream方法,这四类方法最终在Android的底层实现,对应着BitmapFactory类的几个native方法。code
上述四类方法都支持BitmapFactory.Options参数,而Bitmap是按必定采样率进行缩放,即经过BitmapFactory.Options参数实现,主要用到了inSampleSize参数,即采样率。经过对inSampleSize的设置,对图片的像素的高和宽进行缩放。对象
当inSampleSize=1,即采样后的图片大小为原始大小,图片
如inSamoleSize < 1,也按照1来计算
若inSampleSize > 1,即采样后的图片将缩小,缩小比例为1/(inSampleSize的二次方)
注意:官方文档指出:inSampleSize的取值应该老是2的指数,如1,2,4,8等,若是外界传入的inSampleSize的孩子不为2的指数,那么系统会向下取整并选择一个最接近2的指数代替。
咱们须要获取加载图片的宽高信息,而后交给inSampleSize参数选择缩放比缩放。那么如何能先不加载图片却能获取图片的宽高信息,经过inJustDecodeBounds=true
,而后加载图片就能够实现只解析图片的宽高信息,并不会真正的加载图片,因此这个操做时轻量级的,当获取了宽高信息,计算出缩放比后,而后再将inJustDecodeBounds=false,再从新加载图片,就能够加载缩小后的图片。
注意:BitmapFactory获取的图片宽高信息和图片的位置与程序运行的设备有关系,好比同一张图片放在不一样的drawable目录下或者程序运行在不一样屏幕密度的设备上,均可能致使BitmapFactory获取到不一样的结果。
BitmapFactory.Options
的inJustDecodeBounds
参数设置为true
并加载图片BitmapFactory.Options
中取出图片的原始宽高信息,它们对应的outWidth
和outHeight
参数inSampleSize
BitmapFactory.Options
的inJustDecodeBounds
参数设为false
,而后从新加载图片。public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
//加载图片
BitmapFactory.decodeResource(res,resId,options);
//计算缩放比
options.inSampleSize = calculateInSampleSize(options,reqHeight,reqWidth);
//从新加载图片
options.inJustDecodeBounds =false;
return BitmapFactory.decodeResource(res,resId,options);
}
private static int calculateInSampleSize(BitmapFactory.Options options,
int reqHeight, int reqWidth) {
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
if(height>reqHeight||width>reqWidth){
int halfHeight = height/2;
int halfWidth = width/2;
//计算缩放比,是2的指数
while((halfHeight/inSampleSize) >= reqHeight&&
(halfWidth/inSampleSize) >= reqWidth){
inSampleSize*=2;
}
}
return inSampleSize;
}复制代码
这个时候能够经过以下方法高效加载图片:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(),R.mipmap.ic_launcher,100,100));复制代码
除了BItmapFactory的decodeResource方法,其余方法也能够,如decodeFile、decodeByteArray等