Android 优化 - 内存缓存 LruCache

LruCache是Android3.1引入的缓存机制,基于LinkedHashMap实现,当缓存满时遵循最近最少使用原则(LRU)删除元素。它维护访问顺序,读写线程安全,适用于存储像Bitmap这样的对象。使用时需设置缓存大小,通常为进程可用内存的1/8,并重写sizeOf()方法来计算对象大小。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概念

LruCache 是Android 3.1(API12)所提供的一个缓存类,缓存到达限制的时候优先删除近期最少使用。内部维护了一个 LinkedHashMap 以访问顺序排列,满了就删除尾元素(即近期最少使用的Least Recently Used),当获取缓存对象的同时会将该元素更新到队列头部。读写线程安全,对缓存的元素是强引用,不允许null键null值,为null说明没有缓存。
get()

public final V get(K key)

获取缓存过的数据,不存在返回null。线程安全。

put()

public final V put(K key, V value)

添加/更新缓存数据。线程安全。

remove()

public final V remove(K key)

移除缓存的数据。

evictAll()

public final void evictAll()

清除所有缓存数据

resize()

public void resize(int maxSize)

重新设置最大缓存容量

trimToSize()

public void trimToSize(int maxSize)

清除最老的缓存,直到剩余缓存数量满足指定大小

snapshot()

public synchronized final Map<K, V> snapshot()

返回一个Map集合,元素按缓存访问次数最少到最多。

二、使用

  1. 设置 LruCache 缓存大小,一般为当前进程可用内存的1/8。

  2. 重写 sizeOf() 计算出要缓存的对象的大小(总容量和对象大小计算的单位要一直一致)。

private val lruCache by lazy {
    //获取当前进程可用内存大小,并分配1/8用于缓存
    val cacheSize = (Runtime.getRuntime().totalMemory() / 1024 / 8).toInt()
    object : LruCache<String, Bitmap>(cacheSize) {
        //必须重写此方法来测量每张图片的大小(单位要跟总缓存的单位一致)
        //如果是缓存简单的对象,直接返回1
        override fun sizeOf(key: String?, value: Bitmap?): Int {
            //返回Bitmap大小(因为可以复用,换成更小的图也还是占用原来的大小)。
            //而getByteCount()返回的是图片大小。
            return value?.allocationByteCount ?: 0
        }
    }
}

//提供存入方法
fun putBitmap(key: String, value: Bitmap) {
    lruCache.put(key, value)
}

//提供取出方法(返回null意味着不存在缓存)
fun getBitmap(key: String): Bitmap? {
    return lruCache.get(key)
}

三、封装

3.1 工具类

object RamCache {
    private val lruCache by lazy {
        //获取当前进程可用内存大小,并分配1/8用于缓存
        val cacheSize = (Runtime.getRuntime().totalMemory() / 1024 / 8).toInt()
        object : LruCache<String, Pair<Long, Any>>(cacheSize) {
            //必须重写此方法来测量每个对象的大小(单位要跟总缓存的单位一致)
            override fun sizeOf(key: String, value: Pair<Long, Any>): Int {
                return 1
            }
        }
    }

    //提供存入方法
    fun put(key: String, value: Pair<Long, Any>) {
        lruCache.put(key, value)
    }

    //提供取出方法(返回null意味着不存在缓存)
    fun get(key: String): Pair<Long, Any>? {
        return lruCache.get(key)
    }

    fun isExpored(key: String): Boolean {
        val before = get(key)
        return if (before == null) {
            true
        } else {
            System.currentTimeMillis() - before.first >= 60000  //大于一分钟过期
        }
    }

}

3.2 函数封装

suspend fun <T> fetchData(
    request: suspend () -> ApiResponse<T>
) = runCatching {
    request()
}.then { apiResponse ->
    apiResponse.getData()
}.onFailure {
    Log.e("【错误】", it.message.toString())
}

//先判断RAM缓存是否过期(过期和不存在都返回false),未过期就使用RAM缓存
//过期就联网获取然后写入RAM缓存中
suspend fun <T> fetchDataWithRamCache(
    cacheName: String,
    request: suspend () -> ApiResponse<T>,
) = if (cacheName.isRamCacheExpired()) {
    fetchData(request).onSuccess {
        val value = Pair(System.currentTimeMillis(), it as Any)
        RamCache.put(cacheName, value)
    }
} else {
    val obj = RamCache.get(cacheName)?.second as T
    Result.success(obj)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值