Bitmap加载和缓存策略

2018-08-15  本文已影响0人  android小菜鸡一枚
Bitmap加载

BitmapFactory提供了四类方法:decodeFile,decodeResource,decodeStream,decodeByteArray,分别用于支持从文件系统,资源,输入流以及字节数组中加载一个Bitmap对象。
采用BitmapFactory.Options缩放图片可以高效加载Bitmap,其inSampleSize参数即采样率
获取采样率?
1.将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片
2.从BitmapFactory.Options中取出图片的原始宽高信息,他们对应于outWidth和outHeight参数
3.根据采样率的规则并结合目标View的所需大小计算出采样率inSampleSize
4.将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片。

public static Bitmap decodeSamledBitmapFromResource(Resource res,int resId,int reqWidth,int reqHeight) {
    // First decode with inJustDecodeBounds = true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res,resId,options);
    // calculate inSamleSize
    options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);
    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res,resId,options);
}

public static int calculateInSampleSize(
      BitmapFactory.Options options,int reqWidth,int reqHeight){
    //Raw height and width of image
    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;
}

mImageView.setImageBitmap(decodeSamledBitmapFromResource(getResources(),R.id.myimage,100,100));
Android中的缓存策略

当程序第一次从网络加载图片后,就将其缓存到存储设备上,这样下次使用这张图片就不用从网络上获取了,节省流量;很多时候为了提高应用的用户体验,往往还会把图片在内存中再缓存一份,这样应该打算从网络上请求一张图片时程序首先会从内存中去获取,如果内存中没有那就从存储设备中获取,如果存储设备中也没有,那就从网络下载这张图片。
缓存策略主要包含缓存的添加,获取和删除这三类操作。
缓存算法LRU(Least Recently Used),LRU是近期最少使用算法,核心思想是当缓存满时,会优先淘汰那些近期使用的缓存对象。LRU算法的缓存有两种:LruCache和DiskLruCache,Lru用于实现内存缓存,而DiskLruCache实现存储设备缓存。

LruCache

强引用:直接的对象引用
软引用:但一个对象只有软引用存在时,系统内存不足时此对象会被gc回收
弱引用:当一个对象只有弱引用存在时,此对象会随时被gc回收
LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式存储外界的缓存对象,其提供了get和put方法来完成缓存的获取和添加操作,当缓存满时,LruCache会移除较早使用的缓存对象,然后添加新的缓存对象。LruCache是线程安全的

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String,Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key,Bitmap bitmap) {
        return bitmap.getRowBytes()*bitmap.getHeight() / 1024;
    }
}
//从LruCache中获取一个缓存对象
mMemoryCache.get(key)
//向LruCache中添加一个缓存对象
mMemoryCache.put(key,bitmap)
DiskLruCache

磁盘缓存,通过将缓存对象写入文件系统,从而实现缓存的效果。
DiskLruCache的创建过程

private static final long DISK_CACHE_SIZE = 1024* 1024 * 50;//50MB
File diskCacheDir = getDiskCacheDir(mContext,"bitmap");
if(!diskCacheDir.exists()) {
    diskCachDir.mkdirs();
}
mDiskLruCache = DiskLruCache.open(diskCacheDir,1,1,DISK_CACHE_SIZE);

DiskLruCache的缓存添加
DiskLruCache的缓存添加的操作是通过Editor完成的,Editor表示一个缓存对象的编辑对象;首先需要获取图片url所对应的key,然后根据key就可以通过edit()来获取Editor对象,一般采用url的MD5作为key。

private String hashKeyFormUrl(String url) {
    String cacheKey;
    try {
        final MessageDigest mDigest = MessageDigest.getInstance("MD5");
        mDigest.update(url.getBytes());
        cacheKey = bytesToHexString(mDigest.digest());
    } catch(NoSuchAlgorithmException e){
        cacheKey = String.valueOf(url.hashCode());
    }
    return cacheKey;
}

private String bytesToHexString(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for(int i=0;i<bytes.length;i++){
        String hex = Integer.toHexString(0xFF & bytes[i]);
         if(hex.length() == 1) {
            sb.append('0');
         }
        sb.append(hex);
    }
    return sb.toString();
}

//将图片的url转成key以后,就可以获取Editor对象了
String key = hashKeyFormUrl(url);
DiskLruCache.Editor editor = mDiskLruCache.edit(key);
if(editor!=null){
    OutputStream outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
}
ImageLoader实现

内存缓存和磁盘缓存是ImageLoader的核心,只有当这两级缓存都不可用时才需要从网络中拉取图片。
首先尝试从内存缓存中读取图片,接着尝试从磁盘缓存中读取图片,最后从网络中拉取图片。
图片压缩
内存缓存和磁盘缓存
选择线程池和Handler来提供ImageLoader的并发能力和访问UI的能力。

《Android开发艺术探讨》Bitmap的加载和Cache

上一篇下一篇

猜你喜欢

热点阅读