FindJpg(2)-BitMap的高效加载和缓存

一、BitMap的高效加载

  • 因为这个小项目是从本地加载图片资源,所以会有图片压缩的过程。一般若是加载网络图片,应该在服务端按需压缩图片,这样既能节省流量,又能提高图片加载的流畅度。
  • BitMap高效加载的核心思想-采用BitmapFactory.Options来加载所需尺寸的图片:
    • 因为许多时候ImageView并没有原始图片那么大,所以没必要将图片的原始尺寸加载进来,按一定的采样率来加载按需的缩小后的图片,会降低内存的占用,从而在一定程度上避免OOM,提高了Bitmap加载时的性能。
    • 通过BitmapFactory.Options设置inSampleSize(即采样率)来缩放图片。例如一张像素为1024x1024的图片,若设置inSampleSize值为2,则采样后的图片为512x512,占用的内存缩小2*inSampleSize即4倍。
  • 获取inSampleSize的主要流程:
    • 将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片;从字面上就能看到,inJustDecodeBounds参数设为true时,BitmapFactory只解析图片的原始宽高信息,不会真正地加载图片,所以这个操作使得解码时避免了内存分配。
    • 从BitmapFactory.Options取出图片原始宽高信息,对应于outWidth和outHeight参数。
    • 结合目标View所需大小和采样率的规则(官方文档指出inSampleSize的取值应总是2的指数)。
    • 将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片。
具体代码如下:

publicBitmapdecodeSampledBitmapFromFile(String file, intreqWidth, intreqHeight){
    final BitmapFactory.Options options=newBitmapFactory.Options();
   
options.inJustDecodeBounds=true;//使BitmapFactory只解析图片原始宽/高信息,不会真正加载图片
   
BitmapFactory.decodeFile(file,options);

   
options.inSampleSize=calculateInSampleSize(options,reqWidth,reqHeight);//计算采样率

   
options.inJustDecodeBounds=false;
    return
BitmapFactory.decodeFile(file,options);//根据采样率重新加载图片
}


   
public static int calculateInSampleSize(BitmapFactory.Options options,intreqWidth,intreqHeight){
//        图片的原始宽/
       
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;
//            一般建议inSampleSize2的幂
           
while((halfHeight/inSampleSize)>=reqHeight&&(halfWidth/inSampleSize)>=reqWidth){
                inSampleSize*=2;
           
}
        }
        return inSampleSize;
   
}
}


二、BitMap的缓存

  • 缓存策略主要包含缓存的 添加、获取、删除 这三类操作,因为不管内存缓存还是外存缓存,容量都是有限的,所以要删除旧缓存添加新缓存,如何定义缓存的新旧就对应不同的缓存策略。
  • 目前常用的缓存算法是LRU(Least Recently Used),近期最小使用算法,核心思想是缓存满时,优先淘汰近期最少使用的缓存对象。采用LRU算法的缓存有两种:DiskLruCache和LruCache。
  • DiskLruCache
    • 用于实现存储设备缓存,通过将缓存对象写入文件系统实现缓存效果。
    • 应用场景一般是为了让用户避免流量消耗,将从网络上加载的图片(或其它文件等)缓存到存储设备上。
    • 这里的FindJpg是从本地加载图片,所以用不到DiskLruCache。
  • LruCache
    • 内部采用LinkedHashMap以强引用的方式存储外界的缓存对象,它是线程安全的。
    • LinkedHashMap会根据LRU算法来排列对象的顺序,新加入的对象添加到头部,刚被使用过的对象也被移动到头部,所以在链表尾部的对象是最久没有被使用过的,一旦链表满有新对象加入,就会删除链表尾部的对象。
相关代码如下:
   1)   先创建LruCache对象,内存缓存容量设为当前进程可用内存的1/8(安卓官方文档推荐),通过重写sizeOf()方法计算缓存对象(即图片)大小,单位得和总容量一致。

privateImageLoader(Context context){
    mContext=context.getApplicationContext();
    int
maxMemory=(int)(Runtime.getRuntime().maxMemory()/1024);//1024是为了转KB
   
int cacheSize=maxMemory/8;
   
mMemoryCache=newLruCache<String,Bitmap>(cacheSize){
        @Override
       
protected int sizeOf(String key,Bitmap bitmap){//计算Bitmap对象大小
           
return bitmap.getRowBytes()*bitmap.getHeight()/1024;
       
}
    };
}


   2)   编写向LruCache中添加、删除缓存对象(图片)的方法。

   private voidaddBitmapToMemoryCache(String key,Bitmap bitmap){//LruCache中添加一个缓存对象
        if(getBitmapFromMemCache(key)==null){
//            Log.e(TAG,"addBitmapToMemoryCache");
            mMemoryCache.put(key,bitmap);
       
}
    }

   
private BitmapgetBitmapFromMemCache(String key){//LruCache中获取一个缓存对象
        return mMemoryCache.get(key);
   
}//LruCache中获取一个缓存对象


   3)   图片的加载,先尝试从内存加载图片,若内存中没有这张图片,再从外存中加载按需压缩的图片并放入内存缓存起来。

publicBitmaploadBitmap(String uri,intreqWidth,intreqHeight){
        Bitmap bitmap=loadBitmapFromMemCache(uri);
        if
(bitmap!=null){
//            Log.e(TAG,"loadBitmapFromMemCache,url:"+uri);
           
return bitmap;
       
}
        try {
            bitmap = loadBitmapFromDisk(uri, reqWidth,reqHeight);
            if
(bitmap != null) {
//                Log.e(TAG, "loadBitmapFromDisk,url:" + uri);
               
return bitmap;
           
}
        } catch (IOException e) {
            e.printStackTrace();
       
}
        return bitmap;
   
}


privateBitmaploadBitmapFromDisk(String url, intreqWidth, intreqHeight)throwsIOException {
    if (Looper.myLooper() == Looper.getMainLooper()) {
        Log.w(TAG,"load bitmap from UI Thread, it's not recommended!");
   
}
    Bitmap bitmap = null;
   
bitmap = mImageResizer.decodeSampledBitmapFromFile(url,reqWidth,reqHeight);
    if
(bitmap != null) {
        addBitmapToMemoryCache(url, bitmap);
   
}
    return bitmap;
}


privateBitmaploadBitmapFromMemCache(String url){
    Bitmap bitmap=getBitmapFromMemCache(url);
    return
bitmap;
}


Demo地址:FindJpg

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值