LruCache 和 DiskLruCache 的使用以及原理分析

本文介绍了LruCache和DiskLruCache的使用和原理,作为Android中常见的缓存策略。LruCache是内存缓存,基于LinkedHashMap实现,遵循最近最少使用原则。DiskLruCache则是在磁盘上的缓存,操作文件实体,其设计与LruCache类似,但涉及更复杂的文件管理和权限控制。两者都用于提高数据获取效率,减少网络请求。
摘要由CSDN通过智能技术生成

常用的三级缓存主要有LruCache、DiskLruCache、网络,其中LruCache对应内存缓存、DiskLruCache对应持久化缓存。Lru表示最近最少使用,意思是当缓存到达限制时候,优先淘汰近期内最少使用的缓存,LruCache和DisLruCache都是如此。

比如说Android中常来缓存Bitmap,我们先依次从LruCache、DiskLruCache获取,最后才网络下载。

本篇主要从原理和源码分析LruCache和DiskLruCache

LruCache

LruCache<K, V> 可以在内存中缓存数据,内部使用最近最少使用算法,优先淘汰最近时间内最少次使用的缓存对象。

LruCache使用
LruCache<String, Bitmap> mMemoryCache;
mMemoryCache = new LruCache<String, Bitmap>(mMemoryCacheSize) {
   
    @Override
    protected int sizeOf(String key, Bitmap value) {
   
        return value.getByteCount();
    }
};

mMemoryCacheSize表示LruCache的容量值,sizeOf则是每个bitmap占用多大。

其次,LruCache使用起来跟HashMap差不多,主要是put()加入缓存、get()获取缓存

// 加入缓存
mMemoryCache.put(key, bitmap);
// 取出缓存,可能为空
Bitmap bitmap = mMemoryCache.get(key)
LruCache源码

看一下重要的几个变量

private final LinkedHashMap<K, V> map; // 存储缓存
/** Size of this cache in units. Not necessarily the number of elements. */
private int size; // 当前缓存的大小
private int maxSize; // 缓存的最大容量

LruCache使用LinkedHashMap来缓存,LinkedHashMap简直就是为了LruCache定制的,如果不熟悉的话可以看下这篇文章《LinkedHashMap原理和源码分析》

图片

LinkedHashMap继承自HashMap,而且内部维护着一个双向队列,可以设置根据访问动作或者插入动作来调整顺序。

我们根据访问动作会来调整顺序,当插入一个结点时候,将该结点插入到队列的尾部,或者,访问某个结点时,会将该结点调整到队列尾部。这样保证当超过缓存容量的时候,直接从头部删除很久没有用过的结点就可以了。

以上基本就是LruCache的基本原理了。

看一个get()、put()方法:

public final V get(K key) {
   
    if (key == null) {
    // 不支持key、value为null
        throw new NullPointerException("key == null");
    }
    V mapValue;
    synchronized (this) {
   
        mapValue = map.get(key);
        if (mapValue != null) {
   
            hitCount++;
            return mapValue; // 获取到值,直接返回
        }
        missCount++;
    }
    V createdValue = create(key); // 默认是返回null,可以重写表示新建一个默认值
    if (createdValue == null) {
   
        return null;
    }
    // 走到这里,表示create(key) 一个默认值createdValue
    // 以下走插入createdValue流程
    synchronized (this) {
   
        createCount++;
        mapValue = map.put(key, createdValue);

        if (mapValue != null) {
   
            // There was a conflict so undo that last put
            // 说明插入的key有冲突了,需要撤销默认值,恢复插入原来的值mapValue
            map.put(key, mapValue);
        } else {
   
        	// 计算增加size
            size += safeSizeOf(key, createdValue); 
        }
    }
    if (mapValue != null) {
   
    	// entryRemoved默认是空实现,每当移除一个entry都会调用
        entryRemoved(false, key, createdValue, mapValue);
        return mapValue;
    } else {
   
    	// 核心方法,整理缓存,超过限制会清除缓存
        trimToSize(maxSize);
        return createdValue;
    }
}
    public final V put(K key, V value) {
   
        if (key == null || value == null) {
    // 不支持key、value为null
            throw new NullPointerException("key == null || value == null");
        }

        V previous;
        synchronized (this) {
   
            putCount++;
            size += safeSizeOf(key, value); // 增加新的value的size 
            previous = map.put(key, value); // 添加<key, value>
            if (previous != null) {
    
                size -= safeSizeOf(key, previous); // 减去旧的value的size
            }
        }

        if (previous != null) {
   
            // entryRemoved默认是空实现,每当移除一个entry都会调用
            entryRemoved(false, key, previous, value);
        }
		
		// 核心方法,整理缓存,超过限制会清除缓存
        trimToSize(maxSize);
        return previous;
    }
  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRU Cache (最近最少使用缓存) 和 DiskLruCache (基于磁盘的 LRU 缓存) 是两种常见的缓存技术,它们的使用场景和优点如下: 1. LRU Cache使用场景: - 当需要缓存一些数据时,但是又不能无限制地增加内存消耗时,可以使用 LRU Cache 进行缓存。 - 当需要快速访问某些数据时,而这些数据的访问频率比较高时,可以使用 LRU Cache 进行缓存。 - 当需要保证缓存数据的时效性,避免过期数据对程序造成影响时,可以使用 LRU Cache 进行缓存。 2. DiskLruCache使用场景: - 当需要缓存一些大量的数据时,但是这些数据又不能全部存放在内存中时,可以使用 DiskLruCache 进行缓存。 - 当需要保证数据能够持久化存储时,可以使用 DiskLruCache 进行缓存。 - 当需要对缓存数据进行一些额外的操作时,例如压缩、加密等操作时,可以使用 DiskLruCache 进行缓存。 以下是使用 Kotlin 代码展示 LRU CacheDiskLruCache 的实现方法: ```kotlin // LRU Cache 的实现 import android.util.LruCache // 初始化一个 LRU Cache,设置最大缓存数量为 10 个 val lruCache = LruCache<String, String>(10) // 将数据加入缓存中 lruCache.put("key1", "value1") // 获取缓存中的数据 val value = lruCache.get("key1") // 移除缓存中的数据 lruCache.remove("key1") // 清除缓存中的所有数据 lruCache.evictAll() ``` ```kotlin // DiskLruCache 的实现 import com.jakewharton.disklrucache.DiskLruCache import java.io.File // 初始化一个 DiskLruCache,设置缓存目录和最大缓存数量为 10 个 val directory = File(context.cacheDir, "disk_cache") val diskCacheSize = 10 * 1024 * 1024 // 10MB val diskLruCache = DiskLruCache.open(directory, 1, 1, diskCacheSize.toLong()) // 将数据加入缓存中 val editor = diskLruCache.edit("key1") editor?.newOutputStream(0)?.use { outputStream -> outputStream.write("value1".toByteArray()) } editor?.commit() // 获取缓存中的数据 val snapshot = diskLruCache.get("key1") val value = snapshot?.getInputStream(0)?.bufferedReader().use { reader -> reader?.readText() } // 移除缓存中的数据 diskLruCache.remove("key1") // 清除缓存中的所有数据 diskLruCache.delete() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值