Flutter Hive如何处理离线数据存储?

yanding 2023-06-03 450

几乎每个应用程序都需要在本地存储数据。信息的存储和操作是应用程序开发的重要组成部分,Flutter 应用程序也是如此。也许您想要缓存 REST API 响应、构建离线运行的应用程序或存储食品配送应用程序的客户信息。

开发人员可以使用多种选项在 Flutter 中持久化本地数据。shared_preferences:提供了一种很好的方法来存储小对键和值。sqflite:当您的数据库必须处理关系数据之间的复杂关系时,这是一个不错的选择。

但是,如果您正在寻找一个快速且安全的本地数据库,并且还与 Flutter Web() 兼容,那么在这种情况下,使用Flutter hive 处理离线数据存储是最好的方法之一。

Flutter Hive如何处理离线数据存储?

Flutter 中的 Hive 是什么?

Hive 是一个用纯 Dart 编写的轻量级快速键值数据库,它允许您离线存储和同步应用程序数据。

作为用 Dart 编写的键值数据存储,Hive 支持原始和复杂的数据结构,同时提供最高级别的性能。
此外,它还使用 AES-256 加密。

作为示例,这是一张将 Flutter Hive 与其他类似数据库进行比较的图表:

Flutter Hive如何处理离线数据存储?

使用 Flutter Hive 处理离线数据存储入门

在这篇博客中,我们将探索在 Flutter 中使用 TypeAdapter 的 Hive 数据库。我们还将创建一个只有一个页面的简单应用程序,用于显示用户列表、添加新用户、更新现有用户和删除用户。

Flutter Hive如何处理离线数据存储?

如何使用Flutter Hive处理离线数据存储?

第一步:依赖安装

  • 在我们使用 Hive 之前需要两个依赖项。

配置单元和 hive_flutter

  • 您需要将 Hive 和 hive_flutter 包添加到 pubspec.yaml 中,如下所示:

Flutter Hive如何处理离线数据存储?
依赖项:
扑:
      SDK: 颤动
配置单元:^2.2.3
hive_flutter:^1.1.0

添加开发依赖

Flutter Hive如何处理离线数据存储?
dev_dependencies:
颤动测试:
  SDK: 颤动配置单元生成器:^1.1.3build_runner:^2.2.0

第二步:初始化Hive数据库

首先,我们必须在 flutter 应用中调用 runApp 之前初始化 Hive。

Flutter Hive如何处理离线数据存储?
void main() 异步{
WidgetsFlutterBinding.ensureInitialized();
  // 使用应用程序文件中的有效目录初始化 Hive
等待 Hive.initFlutter();
runApp(const MyApp());}

initFlutter() 函数由Hive 提供。基本上,它使用getApplicationDocumentsDirectory 返回的路径来初始化Hive

Flutter Hive如何处理离线数据存储?

您是否需要有关快速安全且没有本机依赖项的本地数据库的帮助?

利用 Hive 的优势 - 一种直接的键值数据库解决方案在本地存储数据。通过 Sqflite 获得即时优势,因为 Hive 还允许您操作目标设备上的数据。

雇用 Flutter 开发人员

蜂巢中的盒子

下面介绍如何使用 Flutter Hive 处理离线数据存储

存储在 Flutter Hive 中的数据被组织成盒子。盒子类似于 SQL 中的表,但它没有结构,可以容纳任何东西。正如我在介绍中提到的,Hive 对数据进行加密。此外,加密的盒子可用于存储敏感信息。

Hive 使用键值集存储其数据。首先,你需要打开你的盒子。

Flutter Hive如何处理离线数据存储?
void main() 异步{
WidgetsFlutterBinding.ensureInitialized();// 使用应用程序文件中的有效目录初始化 Hive
等待 Hive.initFlutter();// 开箱等待 Hive.openBox("用户框");runApp(const MyApp());}

带有 TypeAdapter 的模型类

我们的示例包含多个用户,这些用户具有姓名、爱好和描述等信息。

Flutter Hive如何处理离线数据存储?
导入“包:hive/hive.dart”;“user_model.g.dart”部分;@HiveType(typeId: 0)类 UserModel 扩展 HiveObject {@HiveField(0)
最终字符串名称;
@HiveField(1)
最后的弦乐爱好;
@蜂巢场(2)
最终字符串描述;
用户模型({需要this.name,需要这个爱好,
需要this.description,});}

首先,我们需要导入配置单元。为了生成类型适配器,添加一个名为 user_model.g.dart 的部分。TypeAdapter 不需要手动构造,因为我们使用的是 hive 生成器包。
它使用 hive_generator 包自动为几乎任何类构建 TypeAdapter。
如您所见,userModel 类使用多个字段进行注释。

@HiveType():用@HiveType()明确模型类,让生成器意识到这应该是一个TypeAdapter。

@HiveField(index):用这个字段注解类的字段及其对应的索引是强制性的。

要构建 TypeAdapter 类,请运行以下命令。

Flutter Hive如何处理离线数据存储?
flutter packages pub run build_runner 构建

Flutter Hive如何处理离线数据存储?

这里文件名为user_model.dart,将添加data_model.g.dart文件,其中g代表generated。因此,user_model.g.dart 将是新生成的文件。

现在已经成功构建了 UserModelAdapter,是时候注册它了。

为了实现这一点,我们必须在调用 run app 函数之前编写该适配器。

Flutter Hive如何处理离线数据存储?
void main() 异步{
WidgetsFlutterBinding.ensureInitialized();// 使用应用程序文件中的有效目录初始化 Hive
等待 Hive.initFlutter();// 注册 Hive 适配器Hive.registerAdapter(用户模型适配器());// 开箱等待 Hive.openBox("用户框");runApp(const MyApp());}

增删改查操作

在 Hive 中创建数据

您可以使用对 Hive 框的引用通过调用 add() 函数来添加数据。此方法接受键值对。

Flutter Hive如何处理离线数据存储?
/// 添加新用户未来addUser({required UserModel userModel}) async {
等待框。添加(用户模型);}

当我们点击浮动按钮时,会打开一个对话框,我们可以输入姓名、爱好和描述。之后,我们将按下添加按钮,数据就会出现。

Flutter Hive 中的ValuelistenableBuilder ()流也可以用来监听盒子内部发生的事情。

您可能还喜欢阅读:

Flutter 冻结示例:在 Flutter 应用程序中学习冻结的速成班

在 Hive 中检索数据

可以使用 get() 方法读取 Box 对象。要检索它的值,您只需要提供密钥,就像这样

Flutter Hive如何处理离线数据存储?
var userHobby = box.get('爱好');

如果您使用的是自动递增值,则可以使用框对象的 getAt(index) 方法使用索引进行读取,如下所示

Flutter Hive如何处理离线数据存储?
var userData = box.getAt(index);ValueListenableBuilder(
valueListenable: HiveDataStore.box.listenable(),
  建设者:(上下文,盒子,小部件){
  返回安全区域(
      孩子:box.length > 0 ? ListView.builder(
          收缩包裹:真,
          itemCount: box.length,
          itemBuilder: (BuildContext 上下文, int 索引) {
            var userData = box.getAt(index);
            返回容器(
              填充:const EdgeInsets.all(10),
              边距:const EdgeInsets.all(10),
              装饰:BoxDecoration(颜色:Colors.grey.withOpacity(0.1),
                  边框:Border.all(颜色:Colors.blue.shade900),
                  borderRadius: const BorderRadius.all(Radius.circular(10))),
              孩子:行(
                孩子们: [
                  扩展(
                    弹性:1,
                    孩子:专栏(
                      crossAxisAlignment:CrossAxisAlignment.start,
                      孩子们: [
                        固有高度(
                          孩子:行(
                            孩子们: [
                              Text(userData.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w700),
                              ),
                              VerticalDivider(颜色:Colors.blue.shade900,厚度:2,),
                              Text(userData.description, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
                              ),
                            ],
                          ),
                        ),
                        const SizedBox(高度:15),
                        RichText(text: TextSpan(text: 'Hobby: ', style: const TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.w700),
                            孩子们:<TextSpan>[
                              TextSpan(text: userData.hobby, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w500)),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                  扩展(
                    弹性:0,
                      孩子:行(
                        孩子们: [
                          墨水池(
                            onTap:(){
                              isUpdate.value = true;
                              nameEditingCtr.text = userData.name;
                              hobbyEditingCtr.text = userData.hobby;
                              descriptionEditingCtr.text = userData.description;
                              _showDialog(上下文,索引);
                            },
                            孩子:图标(Icons.edit,尺寸:30,颜色:Colors.blue.shade900,),
                          ),
                          const SizedBox(宽度:10),
                          墨水池(
                            onTap: ()异步{
                                      等待显示对话框(
                                        上下文:上下文,
                                        构建器:(上下文)=> AlertDialog(
                                          title: Text('你确定要删除 ${userData.name} 吗?'),
                                          动作:<小工具>[
                                            文本按钮(
                                              样式:按钮样式(
                                                背景颜色:MaterialStateProperty.all(Colors.blue.shade900),
                                                海拔:MaterialStateProperty.all(3),
                                                shadowColor: MaterialStateProperty.all(Colors.blue.shade900), //定义shadowColor
                                              ),
                                              onPressed: () {dataStore.deleteUser(index: index);},
                                              child: const Text('Yes', style: TextStyle(color: Colors.white),
                                              ),
                                            ),
                                            文本按钮(
                                              风格:ButtonStyle(背景颜色:MaterialStateProperty.all(Colors.blue.shade900),
                                                海拔:MaterialStateProperty.all(3),
                                                shadowColor: MaterialStateProperty.all(Colors.blue.shade900), //定义shadowColor
                                              ),
                                              onPressed: () {Navigator.of(context, rootNavigator: true).pop(); },
                                              孩子:常量文本('否',
                                                样式:TextStyle(颜色:Colors.white),
                                              ),
                                            ),
                                          ],
                                        ),
                                      );
                                    },
                              孩子:图标(图标。删除,大小:30,颜色:Colors.blue.shade900,))
                        ],
                      )),
                ],
              ),
            );
          }):const Center(child: Text("未找到数据"),));
})

更新 Hive 中的数据

put() 方法可以更新你原来为一个键存储的数据。这样,新提供的值将在那个键上更新。

Flutter Hive如何处理离线数据存储?
/// 更新用户数据未来updateUser({required int index,required UserModel userModel}) async {
等待 box.putAt(index,userModel);}

这里我们使用了自动递增的值,你可以使用 box 对象的 putAt(index) 方法来使用索引进行更新。

删除 Hive 中的数据

为了删除数据,您可以将密钥传递给 delete() 方法。

Flutter Hive如何处理离线数据存储?
/// 删除用户未来deleteUser({required int index}) async {
等待 box.deleteAt(索引);}

这里我们使用了自动递增的值,你可以使用box对象的deleteAt(index)方法来使用索引删除。

懒人盒子

每次我们创建一个常规框时,其内容都会存储在内存中。因此性能很高。

当您在 Box 中有大量数据并且不想将它们全部加载到内存中时,LazyBox 是一种快速访问数据的好方法。

Flutter Hive如何处理离线数据存储?
var lazyBox = await Hive.openLazyBox('myLazyBox');var value = await lazyBox.get('lazyVal');

盒子压缩

我们现在已经完成了应用程序的大部分编码。是时候清理了:Hive 是一个 append-only store。可以手动使用 .compact() 方法或者让 Hive 为我们处理。

因此,我重写了 dispose 方法以关闭 Openbox。

Flutter Hive如何处理离线数据存储?
@覆盖无效处置(){
  //释放空间
 Hive.box('userBox').compact();
 // 在关闭页面之前关闭所有打开的框。
 蜂巢关闭();}

所有代码都可以在这里找到:

https://github.com/mohitsolankee22/flutter_hive_db_blog

结论

我希望你已经了解了 Hive DataBase 的基本结构。毫无疑问,Hive 是一个优秀、易用、快速、高效的数据库,尤其是它的速度非常快,几乎支持所有平台。如果您在使用 Flutter Hive 处理离线数据存储方面需要帮助,请随时与我们联系。

言鼎科技)专做软件开发,微信小程序,网站开发,软件外包,手机APP开发,欢迎资讯!

The End