BitmapFactory之高效加载Bitmap图片.
------引语:--------Bitmap简介: Bitmap(位图,位映像) : 在Android中指的是一张图片 . 例如png格式或者jpg格式.
那么如何加载Bitmap呢? 咱们可以利用BitmapFactory类(package android.graphics) , 此类提供了几类加载图片的方法:
PS:此时想到了个题外话 : 解析字符串时的getString函数和optString函数的区别: 如果字符串为null,前者会报错,后者不会报错. ------正题:--------
絮絮叨叨半天 , 到底怎么才能高效的加载一个Bitmap对象呢 (个人认为高效加载即为缩放): 核心思想 : 就是采用BitmapFactory.Options类(内部类)来加载所需尺寸的图片 . 此类用于解码Bitmap时的各种参数控制; 加载图片时ImageView是没有原始图片那么大的 . 此时把整个图片完全的加载进ImageView的话显然没有必要 , 并且在Android手机上ImageView也并没有办法显示原图大小,没办法的话咱们就得缩小加载,要问怎么压缩您接着往下看.
BitmapFactory.Options这个类中: 其中有一个字段叫做 inJustDecodeBounds . SDK中对这个成员的说明是这样的:
If set to true, the decoder will return null (no bitmap), but the out…
也就是说,如果我们把它设为true , 那么BitmapFactory.decodeFile(String path, Options opt)并不会真的返回一个Bitmap给你 , 它仅仅会把它的宽和高取回来给你 , 这样就不会占用太多的内存 , 并且我们也需要适时的回收对象 , 利用下方代码:
if(!bitmap.isRecycled()){及时回收,就不会那么频繁的发生OOM了,也提高了Bitmap加载时的性能.
bitmap.recycle(); //回收图片所占的内存
System.gc(); //提醒系统及时回收
}
------开始--------
得到了原始宽高 , 又有什么用呢 ? 咱们需要的可是缩放啊: 您以为BitmapFactory.Options(内部类)就只能获取原始大小么 ? 那肯定是不可能的 . BitmapFactory.Options类(内部类)档案也可以用来缩放图片: 主要是用到了他的inSampleSize参数,即采样率.
inSampleSize简介: 当inSampleSize等于1时,得到的是原图大小; 当inSampleSize等于1时,效果同1,即得到的是原图大小; 当inSampleSize等于2时,那么采样之后的图片宽高均为原图的1/2,而像素数为原图的1/4,其占有的内存大小也为原图的1/4,例如一张1024*1024*4的图片,即4MB,如果inSampleSize为2,那么采样后的图片占内存512*512*4,即1MB. 官方文档指出:inSampleSize的取值规范应该是2的指数,即1,2,4,8,16等.当然,不遵从也说明咱们随性.
/** *如何获取采样率 */
通过采样率可有效的加载图片,那么到底如何获取采样率呢?您可遵循如下流程: (1).将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片. (2).从BitmapFactory.Options中取出原图片的原始宽高信息,他们对应于outWidth参数和outHight参数 (3).根据采样率的规则并结合目标ImageView的所需大小计算出采样率inSampleSize. (4).将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片. 此时加载的图片即为缩放后的图片. 这里说一下inJustDecodeBounds参数,当此参数为true时,BitmapFactory只会解析原图片的原始宽高.并不会去真正的加载图片.如下是抽取的一个工具类
public class BitMapUtils {
//高效加载BitMap
public static Bitmap decodeSampleBitmapFormResource(Resources resources, int resourcesId, int reqWidth, int reqHeight){
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources,resourcesId,options);
options.inSampleSize = caculateInSampleSize(options,resourcesId,reqHeight,reqWidth);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(resources,resourcesId,options);
}
private static int caculateInSampleSize(BitmapFactory.Options options, int resourcesId, int reqHeight,int reqWidth) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width >reqWidth){
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth){
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
有了上面两个函数,实际使用的时候就很简单了,比如ImageView所期望的图片大小为100*100像素,那么就可以通过如下方式高效的加载并显示图片:
mImageView.setImageBitmap(BitMapUtils.decodeSampleBitmapFormResource(this.getResources(),R.drawable.icon,100,100));
除了BitmapFactory的decodeResource函数,其他三个函数(decodeFile , decodeStream和decodeByteArray.)也是支持采样加载的,并且处理方式也是类似的.
如有问题请多指正,您的指正使我更我正确的前行.