Android缓存机制&一个缓存框架推荐


1、先推荐一个轻量级缓存框架——ACache(ASimpleCache)

ACache介绍:
ACache类似于SharedPreferences,但是比 SharedPreferences功能更加强大,SharedPreferences只能保存一些基本数据类型、Serializable、Bundle等数据,
而Acache可以缓存如下数据:
普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。
主要特色:
  • 1:轻,轻到只有一个JAVA文件。
  • 2:可配置,可以配置缓存路径,缓存大小,缓存数量等。
  • 3:可以设置缓存超时时间,缓存超时自动失效,并被删除
  • 4:支持多进程。
应用场景:
  • 1、替换SharePreference当做配置文件
  • 2、可以缓存网络请求数据,比如oschina的android客户端可以缓存http请求的新闻内容,缓存时间假设为1个小时,超时后自动失效,让客户端重新请求新的数据,减少客户端流量,同时减少服务器并发量。
  • 3、您来说...

2、Android缓存机制

Android缓存分为 内存缓存文件缓存(磁盘缓存)。在早期,各大图片缓存框架流行之前,常用的内存缓存方式是软引用(SoftReference)和弱引用(WeakReference),如大部分的使用方式:HashMap<String url, SoftReference<Drawable>> imageCache;这种形式。从Android 2.3(Level 9)开始,垃圾回收器更倾向于回收 SoftReference或WeakReference对象,这使得SoftReference和WeakReference变得不是那么实用有效。同时,到了Android 3.0(Level 11)之后,图片数据Bitmap被放置到了内存的堆区域,而堆区域的内存是由GC管理的,开发者也就不需要进行图片资源的释放工作,但这也使得图片数据的释放无法预知,增加了造成OOM的可能。因此,在Android3.1以后,Android推出了LruCache这个内存缓存类,LruCache中的对象是强引用的

2.1 内存缓存——LruCache源码分析

    2.1.1 LRU

    LRU,全称Least Rencetly Used,即最近最少使用,是一种非常常用的置换算法,也即淘汰最长时间未使用的对象。LRU在操作系统中的页面置换算法中广泛使用,我们的内存或缓存空间是有限的,当新加入一个对象时,造成我们的缓存空间不足了,此时就需要根据某种算法对缓存中原有数据进行淘汰货删除,而LRU选择的是将最长时间未使用的对象进行淘汰。
    

   2.1.2 LruCache实现原理

    根据LRU算法的思想,要实现LRU最核心的是要有一种数据结构能够基于 访问顺序来保存缓存中的对象,这样我们就能够很方便的知道哪个对象是最近访问的,哪个对象是最长时间未访问的。LruCache选择的是LinkedHashMap这个数据结构, LinkedHashMap是一个双向循环链表,在构造LinkedHashMap时,通过一个boolean值来指定LinkedHashMap中保存数据的方式,LinkedHashMap的一个构造方法如下:     
/*
     * 初始化LinkedHashMap
     * 第一个参数:initialCapacity,初始大小
     * 第二个参数:loadFactor,负载因子=0.75f
     * 第三个参数:accessOrder=true,基于访问顺序;accessOrder=false,基于插入顺序
     */
    public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        super(initialCapacity, loadFactor);
        init();
        this.accessOrder = accessOrder;
    }
显然,在LruCache中选择的是 accessOrder = true;此时,当accessOrder 设置为 true时,每当我们更新(即调用put方法)访问(即调用get方法)map中的结点时,LinkedHashMap内部都会将这个结点移动到链表的尾部,因此,在链表的尾部是最近刚刚使用的结点,在链表的头部是是最近最少使用的结点,当我们的缓存空间不足时,就应该持续把链表头部结点移除掉,直到有剩余空间放置新结点。
可以看到,LinkedHashMap完成了LruCache中的核心功能,那LruCache中剩下要做的就是定义缓存空间总容量,当前保存数据已使用的容量,对外提供put、get方法。
    

    2.1.3 LruCache源码分析

    在了解了LruCache的核心原理之后,就可以开始分析 LruCache的源码了。
     1)关键字段
    根据上面的分析,首先要有总容量、已使用容量、linkedHashMap这几个关键字段,LruCache中提供了下面三个关键字段:     
//核心数据结构
    private final LinkedHashMap<K, V> map;
    // 当前缓存数据所占的大小
    private int size;
    //缓存空间总容量
    private int maxSize;
      要注意的是size字段,因为map中可以存放各种类型的数据,这些数据的大小测量方式也是不一样的,比如Bitmap类型的数据和String类型的数据计算他们的大小方式肯定不同,因此,LruCache中在计算放入数据大小的方法sizeOf中,只是简单的返回了1,需要我们重写这个方法,自己去定义数据的测量方式。因此,我们在使用LruCache的时候,经常会看到这种方式:     
private static final int CACHE_SIZE = 4 * 1024 * 1024;//4Mib
    LruCache<String,Bitmap> bitmapCache = new LruCache<String,Bitmap>(CACHE_SIZE){
        @Override
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount();//自定义Bitmap数据大小的计算方式
        }
    };

     (2)构造方法  
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只有一个唯一的构造方法,在构造方法中,给定了缓存空间的总大小,初始化了 LinkedHashMap核心数据结构,在LinkedHashMap中的第三个参数指定为true,也就设置了accessOrder=true,表示这个LinkedHashMap将是基于数据的访问顺序进行排序。

     (3)sizeOf()和safeSizeOf()方法
    根据上面的解释,由于各种数据类型大小测量的标准不统一,具体测量的方法应该由使用者来实现,如上面给出的一个在实现LruCache时重写sizeOf的一种常用实现方式。通过多态的性质,再具体调用sizeOf时会调用我们重写的方法进行测量,LruCache对sizeOf()的调用进行一层封装,如下:     
private int safeSizeOf(K key, V value) {
  
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
里面其实就是调用sizeOf()方法,返回sizeOf计算的大小。
上面就是LruCache的基本内容,下面就需要提供 LruCache的核心功能了。

     (4)put方法缓存数据
    首先看一下它的源码实现:     
/**
* 给对应key缓存value,并且将该value移动到链表的尾部。
*/
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}

V previous;
synchronized (this) {
// 记录 put 的次数
putCount++;
// 通过键值对,计算出要保存对象value的大小,并更新当前缓存大小
size += safeSizeOf(key, value);
/*
* 如果 之前存在key,用新的value覆盖原来的数据, 并返回 之前key 的value
* 记录在 previous
*/<
  • 20
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值