安卓漫漫路之BitmapFactory高效加载Bitmap.

BitmapFactory之高效加载Bitmap图片.

------引语:--------

Bitmap简介:
Bitmap(位图,位映像) : 在Android中指的是一张图片 . 例如png格式或者jpg格式.

那么如何加载Bitmap呢?
咱们可以利用BitmapFactory类( package android.graphics) , 此类提供了几类加载图片的方法:
  • decodeByteArray(byte[] data, int offset,int length):从指定字节数组的offset位置开始,将长度为length的字节数据解析成Bitmap对象.
  • decodeFIle(String pathName):从pathName指定的文件中解析 , 创建Bitmap对象.
  • decodeFileDescriptor(FileDescriptor fd):用于从FileDescriptor对应的文件中解析 , 创建Bitmap对象.
  • decodeResource(Resource res,int id):用于根据给定的资源ID从指定的资源文件中解析 , 创建Bitmap对象.
  • decodeStream(InputStream is):用于从指定输入流中介解析 , 创建Bitmap对象.
分别用于支持从文件系统 , 资源 , 输入流和字节数组中加载出一个Bitmap对象 . 并且decodeFile函数和decodeResoure函数最终也会调用decodeStream函数.

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()){  
    bitmap.recycle(); //回收图片所占的内存  
    System.gc(); //提醒系统及时回收  
  }  
及时回收,就不会那么频繁的发生OOM了,也提高了Bitmap加载时的性能.

------开始--------

得到了原始宽高 , 又有什么用呢 ? 咱们需要的可是缩放啊:
您以为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.)也是支持采样加载的,并且处理方式也是类似的. 


如有问题请多指正,您的指正使我更我正确的前行.



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值