Android 优化 - 磁盘缓存DiskLruCache

一、概念

用于实现存储设备缓存,即磁盘缓存,通过将缓存对象写入文件系统从而实现缓存的效果。

二、使用

2.1 添加依赖

最新依赖

Groovy 复制代码
implementation "com.jakewharton:disklrucache:2.0.2"

2.2 配置权限

XML 复制代码
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2.3 创建对象 open()

|----------------|----------------------------------------------------------------------------------------|
| public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize) ||
| directory | 存储路径,该文件夹里面所有文件参与计算大小。 |
| appVersion | 应用的版本号,一般设为 1 即可。当版本号发生改变时会清空之前所有的缓存文件,而这个特性在实际开发中作用并不大,很多情况下即使应用的版本号发生了改变缓存文件却仍然是有效的。 |
| valueCount | 表示同一个 key 可以对应多少个缓存文件,一般设为 1 即可。 |
| maxSize | 表示缓存的总大小,比如 50MB,当缓存大小超出这个设定值后,DiskLruCache 会清除一些缓存从而保证总大小不大于这个设定值。 |

  • 缓存的key为String类型,且必须匹配正则表达式a-z0-9_-{1,64}。
  • 一个key可以对应多个value,value类型为字节数组,大小在0 ~ Integer.MAX_VALUE之间
  • 缓存的目录必须为专用目录,因为DiskLruCache可能会删除或覆盖该目录下的文件。
  • 添加缓存操作具备原子性,但多个进程不应该同时使用同一个缓存目录。
Kotlin 复制代码
/**
 * 外置路径:storage/emulated/0/Android/data/包名/cache
 * 内置路径:data/data/包名/ceche
 * @param cachePath 如果外置存储获取不到就从内置存储中获取,调用 context.externalCacheDir?.path ?: context.cacheDir.path
 */
class BitmapDiskCache(
    private val cachePath: String
) {
    private val cacheSize =  (1024 * 1024 * 50).toLong() //50M
    private val file = File(cachePath.plus("BitmapLru")).apply { if (!exists()) mkdirs() }
    private val instance = DiskLruCache.open(file, 1, 1, cacheSize)

    suspend fun put(key: String, value: Bitmap) = withContext(Dispatchers.IO) {
        instance.use { cache ->
            //获取编辑器
            cache.edit(key).run {
                //获取输出流(0表示第一个缓存文件,不能超过创建时设置的valueCount)
                newOutputStream(0).use { outputStream ->
                    //写入Bitmap
                    value.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
                }
                //提交
                commit()
            }
        }
    }

    suspend fun get(key: String): Bitmap? = withContext(Dispatchers.IO) {
        instance.use { cache ->
            //获取快照
            cache.get(key).run {
                //获取输入流(0表示第一个缓存文件,不能超过创建时设置的valueCount)
                getInputStream(0).use { inputStream ->
                    //读取Bitmap
                    BitmapFactory.decodeStream(inputStream)
                }
            }
        }
    }

    suspend fun remove(key: String) = withContext(Dispatchers.IO) {
        instance.use { cache ->
            cache.remove(key)
        }
    }

}
相关推荐
撩得Android一次心动5 小时前
Jetpack Compose 知识点整理2【个人用】
android·笔记·学习·kotlin·compose
是真的小外套5 小时前
2024年软考中级信息安全工程师|选择题考点+案例分析真题解析(含答案)
android·网络
用户2018792831678 小时前
一文讲透 Android Native Heap 监控原理:一间"只进不出"的仓库,和总部派来的侦探
android
YB13759 小时前
Jetpack Compose 动画animate*AsState
android
高晶9 小时前
Android 通讯录应用开发实战:从零搭建 SQLite 数据持久化完整项目
android·设计模式·前端框架
隐擎fox9 小时前
深入 Android 移动端风控与协议层对抗:内核级虚拟环境检测、网络堆栈特征伪装与住宅 IP 协同实战
android·网络·python·网络协议·tcp/ip
换元不配限11 小时前
从 AsyncTask 到现代并发:Android 异步方案的演进与替代实践
android·asynctask·异步编程·方案对比·asynctask替代方案
用户20187928316711 小时前
你的 App 为什么是「电量刺客」?——从一条 WakeLock 追到 Linux 内核的 Android 省电原理全解
android
mmsx12 小时前
Android 安全校验下沉到原生层:防 patch 与构建期自动化
android·安全·自动化