Android图片处理(二)

通过前一篇Android中大图片处理(一)博客内容我们了解到图片在Andriod中的存在形式,这篇博客着重介绍图片内存缓存。

内存缓存:集合存对象

1.内存缓存的核心操作:
  • 存:就有很多的考虑
  • 取:唯一索引性
2.选择什么样的存储结构?
  • map< String,Bitmap >
3.三种引用级别什么意思?
  • 强引用:我们平时使用的集合(arraylist,hashmap,hashset),即使内存oom,也不会去回收对象;
HashMap<String, Bitmap> mSecondLevelCache = new HashMap<String, Bitmap>()
  • 软应用:使用SoftRefrence去包装一个对象,内存不足的时候去回收对象,
HashMap<String, SoftReference<Bitmap>> mSecondLevelCache = new HashMap<String, SoftReference<Bitmap>>();
  • 弱应用:一般不用
4.删除策略/算法

我们定义的存储结构当不能继续缓存图片的时候,需要进行清理。

  • LRU:最近最少使用,Least Recently Used,其实就是按照访问顺序排序,实际开发使用次数多
    • —>和时间有关系(时效性)
  • 删除使用次数最少的:
    • —>和时间没有关系而且大小差不多
  • 删除占用体积最大:
    • —>空间比较宝贵的情况

LruCache缓存策略

安卓很早之前做图片的缓存基本都是使用软应用,但是在2.3之后.google文档明确指出了软应用做缓存的一些不足.建议我们使用LruCache.class;一个内存缓存工具类,提供了基于Lru缓存策略的强引用的内存缓存,存储结构使用的LinkedHashmap

LruCache实现原理

LRUCache实现原理–源码分析

LRUCache通过put方法存入一个键值对,通过get方法获取指定key的值,LRUCache底层实际上是通过操作一个LinkedHashMap来实现存取的,也就是map的get和set方法。

LRUCache实现的LinkedHashMap对象是按LRU顺序来实现LRU缓存,在构造LinkedHashMap对象时,设置第三个参数为true即可,设置为false即为按时间顺序来排序。0.75f是加载因子,即容量达到75%就扩容,扩展为原来的两倍。

this.map = new LinkedHashMap<K, V>(0, 0.75f, true);  

因为是按照LRU顺序来排序,所以在通过LRUCache的put方法存入一个键值对时,会存进到链表的尾部。调用get方法时也会把调用的这个键值对移动到链表尾部,这样保证了尾部的键值对对象是最常调用的,顶部的是最少调用的。这就是LRU算法的原理。

构造LRUCache对象的时候,需要重写sizeOf方法,去指定里面对象的大小怎么计算的,这样才可以计算总大小,从而判断是否超出指定的容量大小。

    int maxSize=4*1024*1024;//4M; 
    LruCache<String,Bitmap> mLruCache = new LruCache<String, Bitmap>(maxSize){

        //取得当前bitmap的大小
        @Override
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount();//返回的值的单位与最大值单位一致
        }

    };

在每次调用LRUCache的put方法的时候,会把存入的对象的大小和已经存在的对象大小叠加一起,然后计算有没有超过定义的容量大小,就是最大容量,超过了最大容量,就会移除链表头部的对象。然后把新的加到链表底部。

LinkedHashmap使用
LinkedHashmap和Hashmap区别:在构造方法里面多了3个参数
/**
 * Constructs an empty <tt>LinkedHashMap</tt> instance with the
 * specified initial capacity, load factor and ordering mode.
 *
 * @param  initialCapacity 初始化容器大小 16KB
 * @param  loadFactor      负载因子   50  15  0.75
 * @param  accessOrder     true:LinkedHash内部会排序-->按照访问顺序排序(这个也是为什么LruCache使用LinkedHashmap做存储结构的原因)
 *                          false:按照插入顺序去排序
 */
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}

/**
 * @param maxSize for caches that do not override {@link #sizeOf}, this is
 *     the maximum number of entries in the cache. For all other caches,
 *     this is the maximum sum of the sizes of the entries in this cache.
 */
public LruCache(int maxSize) {
    if (maxSize <= 0) {
        throw new IllegalArgumentException("maxSize <= 0");
    }
    this.maxSize = maxSize;
    this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
LruCache的使用
1. 告知缓存的具体大小
2. 覆写sizeOf方法,
    1. 告知放入LruCache中具体实体的大小
    2. 和maxSize中定义的单位统一
/**
 * 图片缓存接口对象 写法二
 * ImageCache单独使用是起不到缓存作用的,所以还要结合LruCache
 * Created by LGC on 2017/4/20.
 */

public class MImageCache2 implements ImageLoader.ImageCache {
    // 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
    // LruCache通过构造函数传入缓存值,以KB为单位。
    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    // 使用最大可用内存值的1/8作为缓存的大小。
    int cacheSize = maxMemory / 8;
/***********************可以采用上面的方式定义缓存大小,也可以写死一个缓存大小**********************/
    private int maxSize = 10 * 1024 * 1024;// 10M,定义LruCache最大缓存大小,当超过会启动自动回收
    private final LruCache<String, Bitmap> lruCache;

    public MImageCache2() {
        lruCache = new LruCache<String, Bitmap>(maxSize){
            // 重写此方法来衡量每张图片的大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
//                return value.getByteCount() / 1024;
                return value.getRowBytes() * value.getHeight();
            }
        };
    }

    @Override
    public Bitmap getBitmap(String url) {
        return lruCache.get(url);
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        lruCache.put(url, bitmap);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值