Hive的封装与实践
前言
之前的文章中我介绍过我的项目在缓存管理中还是使用的 path_provider 插件自行封装的缓存框架【传送门】。
本来是也是无伤大雅属于能用的状态,但是考虑到现在的除了网络请求的缓存,还有应用资源的缓存,导致大量的磁盘IO多少影响到性能,这里才想做出优化使用 Hive 接管应用的缓存。
Hive 也是天然适用于缓存这个场景,并且对比 path_provider 原始的方式有一些一些特点:
a) 数据结构和格式:
Hive使用自定义的二进制格式存储数据,这种格式经过优化,可以快速读写。 直接使用path_provider,你需要自己处理数据的序列化和反序列化。 b) 性能:
Hive针对快速读写进行了优化。它使用内存映射文件(memory-mapped files)来提高性能。 使用path_provider,性能取决于你如何实现文件读写。 c) API和易用性:
Hive提供了高级API,使得数据的存储和检索变得简单。 使用path_provider,你需要自己实现所有的数据管理逻辑。 d) 数据类型支持:
Hive支持多种数据类型,并且可以存储复杂对象。 使用path_provider,你需要自己处理不同数据类型的存储。 e) 加密:
Hive提供了内置的加密支持。 使用path_provider,你需要自己实现加密逻辑。 f) 事务和ACID属性:
Hive支持事务,保证了数据的一致性。 使用path_provider,你需要自己实现这些特性。
那么接下来我就详细的介绍一下并且封装之后进行实践。
一、Hive的介绍与使用
Hive 是一个为 Flutter 和 Dart 设计的轻量级、高性能的 NoSQL 数据库。它是用纯 Dart 编写的,不需要本地依赖,这使得它非常适合 Flutter 应用程序。让我为您详细介绍 Hive 并提供一些使用示例。
1.1 Hive 的主要特点:
- 快速:Hive 的读写操作非常快。
- 跨平台:支持所有 Flutter 平台。
- 类型安全:支持所有 Dart 原始类型、List、Map、DateTime 和 Uint8List。
- 轻量级:小巧简单,易于使用。
- 加密支持:可以加密 box 以保护敏感数据。
- 支持懒加载:可以打开巨大的 box,而不会影响启动时间。
- 支持事务
1.2 安装使用 Hive :
在你的 Flutter 项目的 pubspec.yaml 文件中添加依赖:
我们可以已使用 hive_flutter 的快速初始化,也可以自行初始化
或者
使用 Hive 的基本操作:
使用 Hive 进行 CRUD 操作的更多示例:
添加数据注意 add 和 put 的区别:
box.add(person):
这个方法会自动生成一个唯一的键(通常是一个自增的整数)。适用于你不需要指定特定键,只需要按顺序存储对象的情况。返回值是新添加对象的键。这种方法类似于在列表末尾添加一个新项。
box.put('key1', Person(...)):
这个方法允许你指定一个自定义的键(在这个例子中是 'key1')。如果指定的键已经存在,它会覆盖现有的值。适用于你需要使用特定键(如 ID、用户名等)来存储和检索对象的情况。不返回任何值。
当然在我们本地缓存这个场景还是 put 的方法更符合场景。
使用事务:
加密 box
二、Hive的封装与实践
问题来了,我们存储数据是KV的模式,那么是把 key 当做 box 的名称直接 add 一个 value 呢? 还是打开一个指定 name 的box 之后 put 对应的 key 和 value 呢?
再者是我们每次调用都需要打开一个 box 是否方便,是否需要封装使用如何封装?
其实这取决于你的具体需求和数据结构。两种方法都有其适用场景:
a. 把 key 当做 box 的名称,直接 add 一个 value:
优点:简单直接,适合存储单一类型的数据集合。
缺点:可能会创建大量的 box,不利于管理。
适用场景:例如,每个用户一个 box,存储该用户的所有相关数据。
b. 打开一个指定 name 的 box,然后 put 对应的 key 和 value:
优点:更灵活,可以在一个 box 中存储多种类型的数据,便于管理。
缺点:需要自己管理 key 的唯一性。
适用场景:存储应用程序的各种设置,或者同一类型的多个对象。
我个人认为两种都太极端,一个是 Box 太多显著的影响性能,二是 Box 太大也影响读取查询性能。我个人认为应该是按模块分 box ,并且集中管理封装单例 box 对象,例如我们分为 http_cache, app_cache,log_cache 等 固定的 box 名称,用枚举定义,每次打开不同的 Box 之后用单例保存其对象,拿到不同的 box 之后进行对应空间内部的 CURD 则更完美,也更符合”蜂巢“这个概念。
存入:
取出:
日志:
测试带缓存的存入:
测试缓存的取出
我们存入之后立马取出,然后等10秒之后再取一次,日志如下:
比较特殊的是对象的存储,例如:
如果直接存储还是会报错的,因为对象的存储还是需要你自行填写数据适配器并注册到 Hive 中,这里参考 Hive 的文档实现即可:
三、网络请求缓存的实战
得益于我们之前的 Dio 网络请求实战中的封装,我们对于本地缓存的引擎封装只需要替换对应的引擎实现即可。具体可参考我之前的文章【传送门】
我们在 Dio 的缓存拦截器中实现如下:
把存入缓存和取出缓存的换为我们的 localCache 对象即完成修改,注意这里的网络请求我们默认是存入的 app_cache 的 box 中,如果有需求可以自定义容器或者指定容器。
使用的时候我们只需要开启缓存。
结果:
总结
本文介绍了 Hive 的简单使用,以及对应的封装和应用场景的示例,可以看到是可以完全平替 path_provider 的缓存框架的。
总的来说,Hive是一个更高级的解决方案,它在 path_provider 的基础上提供了许多额外的功能和优化。虽然两者都涉及磁盘IO,但Hive提供了更多的抽象和优化,并且内部有内存优化使得数据存储和检索更加快速高效和方便。
在实际开发中,如果你的数据存储需求简单,使用
path_provider
直接操作文件可能足够。但如果你需要一个高效、可扩展、易于管理的解决方案,Hive 是一个更好的选择。
如果对详细的代码有兴趣,也可以参考我的开源项目 【Flutter Room】。
那么今天的分享就到这里啦,当然如果你有其他的更多的更好的实现方式,也希望大家能评论区交流一起学习进步。如果我的文章有错别字,不通顺的,或者代码、注释、有错漏的地方,同学们都可以指出修正。
如果感觉本文对你有一点的启发和帮助,还望你能
点赞
支持一下,你的支持对我真的很重要。
Ok,这一期就此完结。
版权归原作者 码农巧克零 所有, 如有侵权,请联系我们删除。