存储框架封装:LruCacheUtils+DiskLruCacheUtils+责任链设计模式+DeepLink

news2025/1/15 14:04:05

存储框架封装:LruCacheUtils+DiskLruCacheUtils+责任链设计模式+DeepLink

  • 一.存储框架实现思路?
    • 1.缓存策略
    • 2.LRU算法
    • 3.LruCache内存缓存原理
    • 4.DiskLruCache磁盘缓存原理
    • 5.使用单例模式实现LRUCacheUtils
    • 5.使用单例模式实现DiskLRUCacheUtils
  • 二.什么是责任链设计模式?

一.存储框架实现思路?

思路来源与图片的三级缓存,即:内存->磁盘->网络
对于部分数据(如:静态数据或者配置信息)我们可能同样需要进行缓存来提升效率,
具体实现思路如下:
1、使用多级缓存完成资源的复用 如:内存 -> 磁盘 ->…
2、使用责任链设计模式,可以通过自定义添加链节点完成多级缓存
3、使用LruCache完成内存部分存储
4、使用DiskLruCache完成磁盘部分存储

1.缓存策略

缓存策略主要包含缓存的添加、获取和删除三类操作。删除缓存是因为不管是内存缓存还是硬盘缓存,它们的缓存大小都是有限的。当缓存满了之后,再想添加缓存就需要删除一些旧的缓存。

2.LRU算法

Android的三级缓存主要的就是内存缓存和硬盘缓存。这两种缓存机制的实现都应用到了LRU算法。
LRU(Least Recently Used)缓存算法是近期最少使用算法,它的核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。

3.LruCache内存缓存原理

LruCache是Android 3.1提供的一个缓存类,在Android中可以直接使用LruCache实现内存缓存。而硬盘缓存DisLruCache目前还不是Android SDK的一部分,但Android官方文档推荐使用该算法来实现硬盘缓存。

LruCache的核心思想就是维护一个缓存对象列表,这个队列就是由LinkedHashMap维护的。列表的排列方式按照访问顺序实现,即一直没访问的对象,将放在队尾,即将被淘汰,而最近访问的对象将放在队头,最后被淘汰。
在这里插入图片描述
LinkedHashMap由数组+双向链表实现。其中双向链表的结构可以实现访问顺序和插入顺序,使得LinkedHashMap中的<key,value>对按照一定顺序排列起来。

LinkedHashMap通过构造函数来指定双向链表的结构是访问顺序还是插入顺序。

public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}

accessOrder为true是访问顺序,为false是插入顺序。

比如,当设置accessOrder为true时:

public static final void main(String[] args) {
    LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>(0, 0.75f, true);
    map.put(0, 0);
    map.put(1, 1);
    map.put(2, 2);
    map.put(3, 3);
    map.put(4, 4);
    map.put(5, 5);
    map.put(6, 6);
    map.get(1);
    map.get(2);
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
        System.out.println(entry.getKey() + ":" + entry.getValue());

    }
}

输出结果:

0:0

3:3

4:4

5:5

6:6

1:1

2:2

即最近访问的最后输出,这正好满足LRU缓存算法的思想。LruCache的实现就是利用了LinkedHashMap的这种数据结构

4.DiskLruCache磁盘缓存原理

磁盘读写也是用的LRU算法。但是这个和内存的LRU算法有一点小区别。为什么呢?因为内存缓存是我们运行的时候,程序加载内存里面的资源,可以直接通过一个LinkedHashMap去实现。但是磁盘不同,我总不可能吧所有磁盘的资源读出来然后加载在内存里面吧,这样的话,肯定会引发oom了。那么Glide是怎么做磁盘的LRU的呢?

Glide 是使用一个日志清单文件来保存这种顺序,DiskLruCache 在 APP 第一次安装时会在缓存文件夹下创建一个 journal 日志文件来记录图片的添加、删除、读取等等操作,后面每次打开 APP 都会读取这个文件,把其中记录下来的缓存文件名读取到 LinkedHashMap 中,后面每次对图片的操作不仅是操作这个 LinkedHashMap 还要记录在 journal 文件中. journal 文件内容如下图:

data/data/应用包名/cache/。。。。。
在这里插入图片描述
日志文件:
在这里插入图片描述

5.使用单例模式实现LRUCacheUtils

**********kotlin单例模式(掌握)

java版本

public class LRUCacheUtils<V> {
    int maxSize= (int) (Runtime.getRuntime().totalMemory()/8);
    private LRUCacheUtils(){
        lruCache=new LruCache<String, V>(maxSize);
    }
    private static volatile LRUCacheUtils instance=null;
    public static LRUCacheUtils getInstance(){
        if (null==instance){
            synchronized (LRUCacheUtils.class){
                if (null==instance){
                    instance=new LRUCacheUtils();
                }
            }
        }

        return instance;
    }

    LruCache<String,V> lruCache=null;

    /**
     * 按Key存储值
     * @param key
     * @param value
     */
    public void putValue(String key,V value){
        lruCache.put(key,value);
    }

    /**
     * 按Key获取值
     * @param key
     * @return
     */
    public V getValue(String key){
        return lruCache.get(key);
    }

    /**
     * 按Key删除指定值
     * @param key
     */
    public void removeValue(String key){
        lruCache.remove(key);
    }

    /**
     * 清空
     */
    public void clear(){
        lruCache.evictAll();
    }
}

kotlin版本

/**
 * @Author : yaotianxue
 * @Time : On 2023/5/23 07:59
 * @Description : LRUCacheUtils
 */
class LRUCacheUtils<V> {
    var maxSize = (Runtime.getRuntime().totalMemory() / 8).toInt()//内存的1/8
    var lruCache:LruCache<String,V> = LruCache<String,V>(maxSize)//lruCache
    //双重锁单例模式
    companion object{
        val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            LRUCacheUtils<Any>()
        }
    }
    /**
     * 按Key存储值
     */
    fun putValue(key:String,value:V){
        lruCache.put(key,value)
    }
    /**
     * 按Key获取值
     */
    fun getValue(key:String): V? {
        return lruCache.get(key)
    }
    /**
     * 按key删除
     */
    fun removeValue(key:String){
        lruCache.remove(key)
    }
    /**
     * 清空
     */
    fun clear(){
        lruCache.evictAll()
    }
}

5.使用单例模式实现DiskLRUCacheUtils

java版本

public final class DiskLRUCacheUtils<V> {
    private DiskLruCache diskLruCache;
    private static DiskLRUCacheUtils instance=new DiskLRUCacheUtils();
    /**
     * 容量上限200M
     */
    private static final int MAX_SIZE=200*1024*1024;
    private DiskLRUCacheUtils(){
        /**
         * 如下 初始化DiskLruCache
         */
        String diskCachePath = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+"bawei6diskcache";
        File file=new File(diskCachePath);
        if (!file.exists()){
            file.mkdirs();
        }
        try {
            diskLruCache = DiskLruCache.open(file, 1, 1, MAX_SIZE);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static DiskLRUCacheUtils getInstance(){
        return instance;
    }

    public void putValue(String key, V data) {

        String mKey= MD5.encrypt(key);
        OutputStream outputStream = null;
        DiskLruCache.Editor edit=null;
        try {
            edit = diskLruCache.edit(mKey);
            if (edit!=null){

                //对象转byte数组
                byte[] bytes= ObjUtils.obj2ByteArray(data);


                outputStream = edit.newOutputStream(0);
                outputStream.write(bytes);
                edit.commit();
                diskLruCache.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
            if (edit!=null){
                try {
                    edit.abort();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }

        }finally {
            if (outputStream!=null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public V getValue(String key) {
        InputStream is=null;
        try {
            List<Byte> data = new ArrayList<>();
            String mKey = MD5.encrypt(key);
            DiskLruCache.Snapshot snapShot = diskLruCache.get(mKey);
            if (snapShot != null) {
                is = snapShot.getInputStream(0);
                byte[] bytes = new byte[2048];
                int len;
                while ((len = is.read(bytes)) != -1) {
                    for (int i = 0; i < len; i++) {
                        data.add(bytes[i]);
                    }
                }
                bytes = new byte[data.size()];
                for (int i = 0; i < bytes.length; i++) {
                    bytes[i] = data.get(i);
                }
                return ObjUtils.byteArray2Object(bytes);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (is!=null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public void removeValue(String key) {
        String mKey=MD5.encrypt(key);
        try {
            diskLruCache.remove(mKey);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void clear() {
        try {
            diskLruCache.delete();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

kotlin版本

/**
 * @Author : yaotianxue
 * @Time : On 2023/5/23 08:09
 * @Description : DiskLRUCacheUtils
 */
class DiskLRUCacheUtils<V> {
    //磁盘缓存路径
    private var diskCachePath:String = Environment.getExternalStorageDirectory().absolutePath + File.separator +"2010baweidiskcache"
    //磁盘缓存对象
    var  diskCache: DiskLruCache
    //初始化
    init {
        var file = File(diskCachePath)
        if(!file.exists()){//文件夹不存在
            file.mkdirs()//创建文件夹
        }
        diskCache = DiskLruCache.open(file,1,1, MAX_SIZE.toLong())
    }
    companion object{
        const val MAX_SIZE = 200*1024*1024
        val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED){
            DiskLRUCacheUtils<Any>()
        }
    }

    /**
     * 按Key存储值
     */
    fun putValue(key:String,data:V){
        var mKey = MD5.encrypt(key)//使用工具类将keyMD5加密
        var editor = diskCache.edit(mKey)
        editor.let {
            var arrays = ObjUtils.obj2ByteArray(data)//对象转数组
            var outputStream = editor.newOutputStream(0)
            outputStream.write(arrays)
            editor.commit()
            diskCache.flush()

            outputStream.close()
        }
    }

    /**
     * 按Key获取值
     */
    fun getValue(key:String): V? {
        var mKey = MD5.encrypt(key)//使用工具类将keyMD5加密
        var snapshot =  diskCache.get(mKey)//根据键获得snapshot对象
        var inputStream = snapshot.getInputStream(0)//获得输入流
        var bytes = ByteArray(2048)
        var outputStream = ByteArrayOutputStream()//字节数组输出流
        var len = 0
        //inputStream读取数据到outputStream
        while ((inputStream.read(bytes).also { len = it })!=-1){
            outputStream.write(bytes)
        }
        return ObjUtils.byteArray2Object(outputStream.toByteArray())
    }
    /**
     * 按key删除
     */
    fun removeValue(key:String){
        var mKey = MD5.encrypt(key)//使用工具类将keyMD5加密
        diskCache.remove(mKey)
    }

    /**
     * 清空
     */
    fun clear(){
       diskCache.delete()
    }
}

测试使用

        //测试
        var diskLRUCacheUtils = DiskLRUCacheUtils.instance.putValue("111","我是测试数据")
        var str = DiskLRUCacheUtils.instance.getValue("111")
        Toast.makeText(this,"$str",Toast.LENGTH_LONG).show()

二.什么是责任链设计模式?

顾名思义,责任链模式(Chain of Responsibility
Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求
的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不
能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

实现参考链接:https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/557724.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ASP.NET Core 使用Filter和Redis实现接口防重

背景 日常开发中&#xff0c;经常需要对一些响应不是很快的关键业务接口增加防重功能&#xff0c;即短时间内收到的多个相同的请求&#xff0c;只处理一个&#xff0c;其余不处理&#xff0c;避免产生脏数据。 这和幂等性&#xff08;idempotency&#xff09;稍微有点区别&am…

凌恩生物文献分享 | 16S全长扩增子+代谢组/转录组多组学!高分paper的绝佳拍档!

16S全长扩增子联合代谢组/转录组多组学研究&#xff0c;是目前微生态研究趋势。单一研究方法较难发表高水平文章&#xff0c;多组学关联研究逐渐成为“快速”发表高分paper的绝佳拍档&#xff01; 小编精心挑选了3篇医学微生态研究的高分文章&#xff0c;希望能帮助大家激发科…

二线程序员的出路

最近长沙不太平。去年被动离职一拨人之后&#xff0c;HR一直强调降本增效&#xff0c;人人自危&#xff0c;挤走一拨人&#xff0c;反正会有大量内卷失败的一线程序员进来填坑。当然留就有人走&#xff0c;前同事除了几个出去搞培训创业&#xff08;后面解散了&#xff09;的之…

chatgpt赋能Python-python_for_倒序

Python的倒序功能 - 从SEO角度分析 在Web开发中&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;是一个关键的指标。如果你的网站能够被搜索引擎高效地索引&#xff0c;它就会排在搜索结果的前面&#xff0c;带来更多的流量和曝光率。Python&#xff0c;作为一种广泛应用…

【LED子系统】七、触发器实现

个人主页&#xff1a;董哥聊技术 我是董哥&#xff0c;高级嵌入式软件开发工程师&#xff0c;从事嵌入式Linux驱动开发和系统开发&#xff0c;曾就职于世界500强公司&#xff01; 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; 文章目录…

探索未来:人工智能如何改变室内外设计

目录 注册&#xff1a; 使用RoomGPT进行室内和室外设计的步骤&#xff1a; 结果如下&#xff1a; RoomGPT是一款基于人工智能的设计工具&#xff0c;可以帮助专业人士和个人在几秒钟内生成照片般逼真的图像。以下是使用RoomGPT进行室内和室外设计的步骤&#xff1a; 注册&am…

聚观早报 | ChatGPT炒股回报率超500%;网易发布11新游戏

今日要闻&#xff1a;微信支付正式发布“微信刷掌”产品&#xff1b;ChatGPT炒股回报率超500%&#xff1b;网易发布11新游戏&#xff1b;国家超算中心发布中文大语言模型&#xff1b;B站试水付费专属视频 微信支付正式发布“微信刷掌”产品 5 月 21 日&#xff0c;北京轨道交通…

时序电路详解

1、什么是时序电路&#xff1f; 组合电路是根据当前输入信号的组合来决定输出电平的电路&#xff0c;换言之&#xff0c;就是现在的输出不会被过去的输入所左右&#xff0c;也可以说成是&#xff0c;过去的输入状态对现在的输出状态没有影响的电路。 时序电路和组合电路不同&…

「角」毫米波雷达前装增速放缓?哪些供应商位居TOP10

作为传统BSD&#xff08;盲区监测、并线辅助&#xff09;、DOW&#xff08;开门预警&#xff09;功能以及高阶智能驾驶的主要传感器之一&#xff0c;角&#xff08;盲区&#xff09;毫米波雷达在2022年实现了前装搭载的大幅增长。 高工智能汽车研究院监测数据显示&#xff0c;2…

Qt编写视频监控系统74-悬浮工具栏(半透明/上下左右位置/自定义按钮)

一、前言 在监控系统中一般在视频实时预览的时候&#xff0c;希望提供一个悬浮工具条&#xff0c;可以显示一些提示信息比如分辨率、码率、帧率&#xff0c;提供一堆快捷操作按钮&#xff0c;可以录像、抓拍、云台控制、关闭等操作&#xff0c;参考了国内很多监控厂商客户端软…

Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 搜索、分页与结果过滤

文章目录 ⛄引言一、酒店搜索和分页⛅需求分析⚡源码编写 二、酒店结果过滤⌚需求分析⏰修改搜索业务 ✅效果图⛵小结 ⛄引言 本文参考黑马 分布式Elastic search Elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据…

【社群运营】AI智能对话,打造自动化社群

人工智能大背景下&#xff0c;各行各业都在往智能化发展&#xff0c;无论是办公产品&#xff0c;还是生产器械都选择接入了更加智能的AI来提高生产效率。那么&#xff0c;在日常的社群管理工作中&#xff0c;我们又能否跟上这一波热度&#xff0c;让社群自动化高效运营&#xf…

深度学习实战32-构建ChatT5模型,实现智能问答系统,类ChatGPT(CPU部署)

大家好,我是微学AI,今天给大家介绍一下深度学习实战32-构建ChatT5模型,实现智能问答系统,类ChatGPT(CPU部署),ChatT5使用了T5架构来处理输入文本,具有高度的并行性和扩展性,使其能够快速处理大规模数据集。与传统NLP模型不同,ChatT5采用端到端的方式进行训练,从而可以…

ov2640子设备核心操作详细分析

ov2640子设备核心操作详细分析 文章目录 ov2640子设备核心操作详细分析ov2640_subdev_core_ops核心操作获取寄存器值ov2640_g_register设置寄存器值ov2640_s_registeri2c_smbus_xferi2c_imx_xferi2c_smbus_xfer_emulatedi2c_transfer__i2c_transfer 设置ov2640的电源ov2640_s_p…

解决城市内涝的措施有哪些?需要用到哪些监测设备?

随着城市化的不断推进&#xff0c;城市内涝问题日益凸显。极端天气事件如暴雨、台风等对城市基础设施和居民生活造成了严重影响。那么&#xff0c;解决城市内涝的措施有哪些?需要用到哪些监测设备?针对上述问题&#xff0c;本文会为大家一一进行讲解。 解决城市内涝的措施有哪…

全志V3S嵌入式驱动开发(uboot移植)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 安装了ubuntu操作系统&#xff0c;有了开发板&#xff0c;下面就可以进行我们的开发工作了。第一步&#xff0c;我们要面临的问题就是uboot移植。一…

2098-DSD-020X 具有集成的DeviceNet通信接口

描述:2098-DSD-020X-DN是艾伦-布拉德利Ultra 3000运动控制系列的一部分。该产品是一种数字伺服驱动器&#xff0c;可在120VAC / 240 VAC、单相、50-60 Hz的输入电源电压和18安培的输入电流下运行。该伺服驱动器提供120 / 240 VAC的输出电压、3相、0-400 Hz的可编程频率范围、10…

APACHE-ATLAS-2.1.0简介(二)

APACHE-ATLAS-2.1.0简介(一) 什么是元数据&#xff1f; 元数据(METADATA)&#xff0c;用一句话定义就是&#xff1a;描述数据的数据。元数据打通了数据源、数据仓库、数据应用之间的壁垒&#xff0c;记录了数据从产生到消费的全过程。 ATLAS的问题列表 APACHE-ATLAS-STACKO…

【CANN训练营0基础赢满分秘籍】应用开发深入讲解→模型推理

1 模型离线推理 各步要解析如下: Host&Device内存管理与数据传输: Host&Device上的内存申请与释放&#xff0c;内存间的相互拷贝;模型加载:将离线的om文件加载到Device上;在样例的资源初始化模块中进行。模型输入输出准备∶根据禹线om的输入输出&#xff0c;在Device…

【记者团】社团管理手册

志愿时长&#x1f381;&#xff1a;团内有时会有志愿服务等活动&#xff0c;志愿时长可以找自己班长或班上负责人统计&#xff0c;记者团孙老师会和团委老师对接&#xff0c;团委会记录志愿时长。 志愿时长用于校级奖学金、班级奖学金、校评优评先、青马班面试(青马对入党有帮助…