Bitmap 的高效加载

读完 任玉刚 的《Android 开发艺术探索》之Bitmap的加载 。(小笔记)

Bitmap: android中指的是一张图片 (png / jpg 等)。

如何加载一个图片?
BitmapFactorγ 类提供了四类方法:

decodeFile(支持从文件系统加载),
decodeResource(支持从资源加载),
decodeStream(支持从输入流加载),
decodeByteArray(支持从字节数组加载) 。

其中 decodeFile、decodeResource 又间接调用了decodeStream 方法,这四类方法最终是在 Android 的底层实现的,对应着 BitmapFactory 类的几个native 方法。

如何高效地加载 Bitmap 呢?
——核心思想就是采用 BitmapFactory.Options 来加载所需尺寸的图片。

把整个图片加载进来后再设给 ImageView 这显然是没必要的,因为 ImageView 并没有办法显示原始的图片。

通过 BitmapFactory.Options按一定的采样率加载图片,ImageView 显示缩小后的图片,很大程度降低 OOM的出现 ,提高了 Bitmap 加载时的性能。

BitmapFactory提供的加载图片的四类方法都支持 BitmapFactory.Options
参数,通过它们就可以很方便地对一个图片进行采样缩放。

BitmapFactory.Options 主要用到 inSampleSize 参数,即采样率。

inSampleSize =1,采样后的图片大小为图片的原始大小;
inSampleSize <1,采样后的图片大小为图片的原始大小;
inSampleSize >1,比如为2 ,那么采样后的图片其宽/高均为原大小的 1/2 ,而像素数为原图的 1/4,占的内存大小为原图的 1/4 。
inSampleSize = n; n>1;
像素数为原图的 1/n*n;
内存大小为原图的 1/n*n;

拿一张 1024x1024 像素的图片来说,假定采用 ARGB8888格式存储,那么它占有的内存为 1024 x1024 x4,即 4MB,如果 inSampleSize为2 ,那么采样后的图片其内存占用只有 512x512 x4, (即 1MB 。可以发现采样率inSampleSize 必须是大于1的整数,图片才会有缩小的效果,并且采样率同时作用于宽/高,这将导致缩放后的图片大小,以采样率的2次方形式递减,即缩放比例为 1/ (inSampleSize 次方) 。有一种特殊情况,那就是当 inSampleSize 小于1时,其作用相当于 1,即无缩放效果。

开发建议:

最新的官方文料中指出, inSampleSize 的取值应该总是为2的指数,比如1、2、4、6、8、16 ,等等。如果外界传递给系统的 inSampleSize不为的指数,那么系统会向下取整,并选择一个最接近2的指数来代替,比如3 ,系统会选择来代替,但是经过验证发现这个结论并非在所有的 Android 版本上都成立,因此把它当成即开发建议可。

/** 
* 获取压缩后的图片 
* @param res 
* @param resId 
* @param reqWidth            所需图片压缩尺寸最小宽度 
* @param reqHeight           所需图片压缩尺寸最小高度 
* @return 
*/  
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,  
        int reqWidth, int reqHeight) {  

    // 首先不加载图片,仅获取图片尺寸  
    final BitmapFactory.Options options = new BitmapFactory.Options();  
    // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息  
    options.inJustDecodeBounds = true;  
    // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象  
    BitmapFactory.decodeResource(res, resId, options);  

    // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4  
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);  

    // 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了  
    options. inJustDecodeBounds = false;  
    // 利用计算的比例值获取压缩后的图片对象  
    return BitmapFactory.decodeResource(res, resId, options);  
}  

/** 
* 计算压缩比例值 
* @param options       解析图片的配置信息 
* @param reqWidth            所需图片压缩尺寸最小宽度 
* @param reqHeight           所需图片压缩尺寸最小高度 
* @return 
*/  
public static int calculateInSampleSize(BitmapFactory.Options options,  
             int reqWidth, int reqHeight) {  
       // 保存图片原宽高值  
       final int height = options. outHeight;  
       final int width = options. outWidth;  
       // 初始化压缩比例为1  
       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.setlmageBitmap(
    decodeSampledBitmapFromResource (getResources(),R.id.myimage,100, 100));

除了 BitmapFactory decodeResource 方法,其他 三个decode 系列的方法也是支持采样加载的,并且处理方式也是类似的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值