flutter实战 之 hive 本地数据持久化

为什么要用hive

Hive 是一个在移动应用和桌面应用中实现高性能、轻量级本地数据存储的解决方案。它将数据存储在应用的文件系统中,通常是应用的沙盒目录(sandbox directory)。
具体来说,Hive 将数据存储在应用的文件系统中的特定目录中。在 Flutter 中,Hive 默认将数据存储在应用的沙盒目录下的一个名为 hive 的子目录中。
这个目录中包含了各种用于存储数据的文件,包括:
*.hive 文件:这些是实际的 Hive 数据库文件,其中存储了通过 Hive 存储的数据。不同的 Hive Box(类似于数据库表)会有不同的文件。
*.lock 文件:这些是用于在多个操作之间进行同步的锁文件。它们确保在进行读取和写入操作时,数据不会出现冲突。
*.log 文件:这些文件用于记录 Hive 操作的日志,以便在需要时进行故障排除。
Hive 以一种非常轻量级的方式将数据存储在文件系统中,这使得数据读取和写入的性能非常高效。同时,Hive 还支持将数据序列化为不同的格式,例如二进制、JSON 等,以提高存储和读取效率。

总结起来,Hive 将数据存储在应用的文件系统中,使得您的应用能够高效地在本地进行数据存储和检索。

开始实战

添加依赖

dependencies:
  hive: ^[version]
  hive_flutter: ^[version]

dev_dependencies:
  hive_generator: ^[version]
  build_runner: ^[version]

什么是boxes

数据存储在box里面,没有固定的结构,可以存储任何数据
对于小的项目,一个 box 就够用了,但是对于大的项目,需要多个

怎么使用 Box

在使用 Box 之前必须要将其打开

var box = await Hive.openBox<E>('testBox');

Why use Hive

Hive 是一个在移动应用和桌面应用中实现高性能、轻量级本地数据存储的解决方案。它将数据存储在应用的文件系统中,通常是应用的沙盒目录(sandbox directory)。
具体来说,Hive 将数据存储在应用的文件系统中的特定目录中。在 Flutter 中,Hive 默认将数据存储在应用的沙盒目录下的一个名为 hive 的子目录中。
这个目录中包含了各种用于存储数据的文件,包括:
*.hive 文件:这些是实际的 Hive 数据库文件,其中存储了通过 Hive 存储的数据。不同的 Hive Box(类似于数据库表)会有不同的文件。
*.lock 文件:这些是用于在多个操作之间进行同步的锁文件。它们确保在进行读取和写入操作时,数据不会出现冲突。
*.log 文件:这些文件用于记录 Hive 操作的日志,以便在需要时进行故障排除。
Hive 以一种非常轻量级的方式将数据存储在文件系统中,这使得数据读取和写入的性能非常高效。同时,Hive 还支持将数据序列化为不同的格式,例如二进制、JSON 等,以提高存储和读取效率。
总结起来,Hive 将数据存储在应用的文件系统中,使得您的应用能够高效地在本地进行数据存储和检索。

开始实战

添加依赖

dependencies:
  hive: ^[version]
  hive_flutter: ^[version]

dev_dependencies:
  hive_generator: ^[version]
  build_runner: ^[version]

什么是 Boxes

数据被存储在盒子内部,没有固定的结构,可以存储任何类型的数据。
对于小型项目,一个盒子足够,但对于大型项目,需要多个盒子。

怎么使用 Box

使用 Box之前必须打开

var box = await Hive.openBox<E>('testBox');

如果这个盒子之前已经打开了可以使用,如果没有打开不可以用

var box = Hive.box('myBox');

使用完后要记得关闭,所有活动的读写操作完成后,盒子的所有缓存键和值将从内存中删除,并且盒子文件将关闭。

var box = await Hive.openBox('myBox');
await box.put('hello', 'world');
await box.close();

打开一个指定类型的 Box ,但是不可以同时用不同的类型打开同一个 Box

var box = await Hive.openBox<User>('users');

box.add(User());

box.add(5); // 编译时错误

await Hive.openBox<User>('users');

Hive.box<User>('users'); // OK

Hive.box('users'); // ERROR
Hive.box<Dog>('users'); // ERROR

读写数据

read

从 box 里面读取数据是很直接的操作,你提供所需要数据的 key ,就可以返回 对应的value000

var box = Hive.box('myBox');

String name = box.get('name');

DateTime birthday = box.get('birthday');

注意,如果你提供的 key 对应的value不存在的话,会返回 null,为了避免这种情况的发生,我们可以设置一个返回值

double height = box.get('randomKey', defaultValue: 17.5);

在使用 get() 方法获取数据时,返回的列表类型是 List(键值对为 Map<dynamic, dynamic>)。如果您希望将它们转换为特定类型,您需要使用 list.cast() 来进行类型转换。

write

将数据写入盒子几乎就像写入映射一样。所有键都必须是ASCII字符串,最大长度为255个字符,或者是无符号32位整数。

var box = Hive.box('myBox');

box.put('name', 'Paul');

box.put('friends', ['Dave', 'Simon', 'Lisa']);

box.put(123, 'test');

box.putAll({'key1': 'value1', 42: 'life'});

您可能想知道为什么在没有异步代码的情况下可以进行编写。这是 Hive 的主要优势之一。
更改会在后台尽快写入磁盘,但所有侦听器都会立即收到通知。如果异步操作失败(不应该失败),所有侦听器都会再次收到旧值的通知。
如果您想确保写入操作成功,只需等待其Future.

var box = await Hive.openBox('box');

box.put('key', 'value');
print(box.get('key')); // value

var lazyBox = await Hive.openLazyBox('lazyBox');

var future = lazyBox.put('key', 'value');
print(lazyBox.get('key')); // null

await future;
print(lazyBox.get('key')); // value

删除

可以选择用null覆盖或者直接删除

  box.put("age","10");
  print(box.get("age"));
  box.put("age", null);
  print(box.get("age",defaultValue: "33"));
  box.delete("age");
  print(box.get("age",defaultValue: "33"));

结果如下:
在这里插入图片描述

练手

import 'package:flutter/material.dart';

import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';

void main() async {
  await Hive.initFlutter();
  await Hive.openBox('settings');
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo Settings',
      home: Scaffold(
        body: ValueListenableBuilder<Box>(
          valueListenable: Hive.box('settings').listenable(),
          builder: (context, box, widget) {
            return Center(
              child: Switch(
                value: box.get('darkMode', defaultValue: false),
                onChanged: (val) {
                  box.put('darkMode', val);
                },
              ),
            );
          },
        ),
      ),
    );
  }
}

怎么理解上面的代码
MyApp 类是一个无状态的小部件,构建了一个带有开关(Switch)的用户界面,用于切换夜间模式。以下是代码的详细解释:
MaterialApp 是 Flutter 应用的顶层小部件,定义了应用的一些元信息。
Scaffold 是一个用于构建典型应用页面布局的小部件。
ValueListenableBuilder 是一个构建小部件的帮助工具,它可以根据 Hive 盒子中的变化来重新构建 UI。
在 ValueListenableBuilder 内部,您监听了 Hive 盒子 ‘settings’ 的变化,每当盒子中的数据发生变化时,UI 就会重新构建。
Switch 是一个切换按钮,用于在开启和关闭之间进行切换。
value 参数是用于设置 Switch 是否选中的值,这里是从 Hive 盒子中获取 ‘darkMode’ 键对应的值,默认值是 false。
onChanged 参数是一个回调函数,当用户切换开关时,将会调用这个函数。在这个函数中,您使用 box.put 将新的开关状态存储到 Hive 盒子中。
这个示例应用展示了如何使用 Hive 存储和读取设置数据,并通过 UI 反映设置的变化。这是一个简单的示例,您可以根据自己的需求扩展和修改。

我们再次单独理解一下
当用户点击开关(Switch)时,onChanged 回调会被触发。这个回调接收一个参数 val,表示开关的新状态,即用户是否切换了开关的选中状态。
如果开关被打开,val 的值为 true;如果开关被关闭,val 的值为 false。这是因为开关表示一个布尔值的状态,选中代表 true,未选中代表 false。
所以,当您点击开关时,onChanged 回调会根据用户的操作将 true 或 false 传递给 val,然后您使用 box.put(‘darkMode’, val) 将这个值存储到 Hive 盒子中,以便在以后可以读取它并根据用户的设置来调整应用的行为。

如果您希望您的小部件根据存储在Hive中的数据进行刷新,您可以使用ValueListenableBuilder。box.listenable() 方法提供了一个ValueListenable,它还可以与provider包一起使用。

如果只想监听特定 key ,可以用下面的代码

ValueListenableBuilder<Box>(
  valueListenable: Hive.box('settings').listenable(keys: ['firstKey', 'secondKey']),
  builder: (context, box, widget) {
    // build widget
  },
)

补充

自动增量和索引
我们已经知道 Hive 支持无符号整数键。如果您愿意,可以使用自动递增键。这对于存储和访问多个对象非常有用。您可以像列表一样使用 Box。
还有getAt()、putAt()和deleteAt()方法可以通过索引访问或更改值。

import 'package:hive/hive.dart';

void main() async {
  var friends = await Hive.openBox('friends');
  friends.clear();

  friends.add('Lisa');            // index 0, key 0
  friends.add('Dave');            // index 1, key 1
  friends.put(123, 'Marco');      // index 2, key 123
  friends.add('Paul');            // index 3, key 124

  print(friends.getAt(0));
  print(friends.get(0));
  
  print(friends.getAt(1));
  print(friends.get(1));
  
  print(friends.getAt(2));
  print(friends.get(123));
  
  print(friends.getAt(3));
  print(friends.get(124));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Flutter中实现本地数据持久化有多种方式,比如使用shared_preferences、sqflite、path_provider等插件。下面以shared_preferences为例,介绍如何实现输入数据的本地存储和读取。 首先,在`pubspec.yaml`文件中添加依赖: ```yaml dependencies: shared_preferences: ^2.0.6 ``` 然后,在需要存储数据的页面,我们可以使用如下代码将输入的数据存储到本地: ```dart import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class InputPage extends StatefulWidget { @override _InputPageState createState() => _InputPageState(); } class _InputPageState extends State<InputPage> { TextEditingController _textEditingController = TextEditingController(); String _inputData = ''; @override void initState() { super.initState(); _loadData(); } @override void dispose() { _textEditingController.dispose(); super.dispose(); } Future<void> _loadData() async { SharedPreferences prefs = await SharedPreferences.getInstance(); setState(() { _inputData = prefs.getString('input_data') ?? ''; _textEditingController.text = _inputData; }); } Future<void> _saveData(String data) async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString('input_data', data); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('输入页面'), ), body: Padding( padding: EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '请输入数据:', style: TextStyle( fontSize: 16.0, ), ), SizedBox(height: 10.0), TextField( controller: _textEditingController, onChanged: (value) { _saveData(value); }, decoration: InputDecoration( hintText: '请输入', ), ), SizedBox(height: 20.0), Text( '输入的数据是:$_inputData', style: TextStyle( fontSize: 16.0, ), ), ], ), ), ); } } ``` 在上面的代码中,我们首先在`initState`方法中调用了`_loadData`方法,从本地存储中加载数据并将其设置到文本输入框中。`_loadData`方法中,我们使用`SharedPreferences`插件获取实例,并调用`getString`方法获取之前存储的数据,如果之前没有存储数据则返回默认值''。然后,我们在`TextField`的`onChanged`回调中调用`_saveData`方法,将输入的数据保存到本地。`_saveData`方法中,我们同样使用`SharedPreferences`插件获取实例,并调用`setString`方法将数据存储到本地。 这样,输入的数据就可以实现本地持久化了。每次打开应用时,都会从本地存储中加载之前输入的数据,并将其设置到文本输入框中。如果用户修改了输入的数据,就会自动保存到本地。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wniuniu_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值