flutter 实战之 hive 进阶

啥是 TypeAdapter

在Hive中,TypeAdapters是用于处理自定义对象序列化和反序列化的概念。Hive是一个适用于Flutter和Dart编程的轻量级、快速的键值存储库。

Hive supports all primitive types, List, Map, DateTime and Uint8List. If you want to store other objects, you have to register a TypeAdapter which converts the object from and to binary form.
You can either write a TypeAdapter yourself or generate it.

总而言之,为什么要使用 TypeAdater 呢?
box 里面装的只能是一般的数据类型,如果我们需要装其他的数据类型就要借助 TypeAdapter 来转换

Register Adapter
当你想让Hive使用一个TypeAdapter时,你需要将其注册。这需要两个要素:适配器的实例和一个类型ID(typeId)。每种类型都有一个唯一的类型ID,用于在从磁盘中恢复值时找到正确的适配器。所有的类型ID在0到223之间都是允许的。

Hive.registerAdapter(MyObjectAdapter());
import 'package:hive/hive.dart';

class User {
  String name;

  User(this.name);

  @override
  String toString() => name; // Just for print()
}

void main() async {
  // Register Adapter
  Hive.registerAdapter(UserAdapter()); 

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

  box.put('david', User('David'));
  box.put('sandy', User('Sandy'));

  print(box.values);
}

// Can be generated automatically
class UserAdapter extends TypeAdapter<User> {
  @override
  final typeId = 0;

  @override
  User read(BinaryReader reader) {
    return User(reader.read());
  }

  @override
  void write(BinaryWriter writer, User obj) {
    writer.write(obj.name);
  }
}

如果没有这段名为UserAdapter的代码,将会出现以下问题:
无法序列化和反序列化User对象:Hive默认情况下只能处理基本数据类型和支持的集合类型,如整数、字符串、列表等。如果没有UserAdapter代码,Hive将无法理解如何将自定义的User对象序列化为二进制数据以进行存储,也无法从二进制数据中还原出User对象。
无法将User对象存储到Hive盒子中:在box.put(‘david’, User(‘David’))这行代码中,如果没有UserAdapter,Hive将不知道如何将User对象转换为可存储的数据类型,因此会导致错误或异常。
无法从Hive盒子中检索User对象:在print(box.values)这行代码中,如果没有UserAdapter,Hive将无法将二进制数据转换回User对象,因此无法正确地打印盒子中的值。
综上所述,没有UserAdapter代码将导致Hive无法处理自定义对象的序列化和反序列化,从而无法正常存储和检索自定义对象。因此,为了在Hive中存储和操作自定义对象,你需要编写适当的适配器代码,以告诉Hive如何进行序列化和反序列化操作。

生成适配器

1.为一个类生成 TypeAdapter,需要对它使用 @HiveType 注解并提供一个 typeId(介于 0 和 223 之间)。
2.对所有需要存储的字段使用 @HiveField 进行注解。
3.运行构建任务:flutter packages pub run build_runner build。
注册生成的适配器。

一个简单的例子

import 'package:hive/hive.dart';

part 'person.g.dart';

@HiveType(typeId: 1)
class Person {
  @HiveField(0)
  String name;

  @HiveField(1)
  int age;

  @HiveField(2)
  List<Person> friends;
}

Hive对象

当您在 Hive 中存储自定义对象时,您可以扩展HiveObject以轻松管理您的对象。HiveObject提供对象的键和有用的辅助方法,例如save()或delete()。

看一下下面的示例

import 'package:hive/hive.dart';

void main() async {
  Hive.registerAdapter(PersonAdapter());
  var persons = await Hive.openBox('persons');

  var person = Person()
    ..name = 'Lisa';

  persons.add(person); // Store this object for the first time

  print('Number of persons: ${persons.length}');
  print("Lisa's first key: ${person.key}");

  person.name = 'Lucas';
  person.save(); // Update object

  person.delete(); // Remove object from Hive
  print('Number of persons: ${persons.length}');

  persons.put('someKey', person);
  print("Lisa's second key: ${person.key}");
}

@HiveType()
class Person extends HiveObject {
  @HiveField(0)
  String name;
}

class PersonAdapter extends TypeAdapter<Person> {
  @override
  final typeId = 0;

  @override
  Person read(BinaryReader reader) {
    return Person()..name = reader.read();
  }

  @override
  void write(BinaryWriter writer, Person obj) {
    writer.write(obj.name);
  }
}
Hive.registerAdapter(PersonAdapter());:将自定义的 PersonAdapter 注册到 Hive 中,使 Hive 知道如何处理 Person 类的序列化和反序列化。

var persons = await Hive.openBox('persons');:打开一个名为 'persons' 的 Hive 盒子,用于存储 Person 对象。

创建一个名为 person 的 Person 对象,并设置其 name 属性为 'Lisa'。

persons.add(person);:将 person 对象添加到 Hive 盒子中,实现第一次存储。

print('Number of persons: ${persons.length}');:打印 Hive 盒子中存储的 Person 对象数量。

print("Lisa's first key: ${person.key}");:打印 person 对象的键(key)。

修改 person 对象的 name 属性为 'Lucas'。

person.save();:将修改后的 person 对象保存回 Hive 盒子中,实现对象的更新。

person.delete();:从 Hive 盒子中删除 person 对象。

打印更新后 Hive 盒子中存储的 Person 对象数量。

persons.put('someKey', person);:使用自定义键 'someKey' 将 person 对象再次存储到 Hive 盒子中。

打印第二次存储后 person 对象的键。

定义了一个名为 Person 的类,并使用 @HiveType() 注解将其标记为 Hive 支持的类型。

@HiveField(0):使用 @HiveField() 注解将 name 字段标记为 Hive 支持的字段,分配给它的 Hive 字段索引是 0。

定义了名为 PersonAdapter 的适配器类,用于将 Person 对象序列化和反序列化为二进制数据。适配器的 typeId 设置为 0。

总之,这段代码展示了如何使用 Hive 存储和操作对象数据,包括对象的添加、更新和删除,以及如何定义适配器来处理序列化和反序列化逻辑。


var person = Person()
  ..name = 'Lisa';
这段代码可以拆解为以下步骤:

Person():这部分是创建一个 Person 对象的过程。相当于调用 Person 类的默认构造函数来创建一个新的对象。

..name = 'Lisa':这是级联操作符 .. 的用法。级联操作符允许你在一个对象上执行多个操作,而不必重复引用该对象。在这个例子中,它等同于先创建了 Person 对象,然后在该对象上设置了 name 属性为 'Lisa'。

这两个步骤的结合相当于在创建 Person 对象后,立即给该对象的 name 属性赋值为 'Lisa'。

这种写法在 Dart 中非常方便,因为它允许你在一个表达式中按顺序设置对象的多个属性,而不必在每一步都显式地引用对象。这在链式操作中非常实用。

实战

实战1,主题切换

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

const darkModeBox = 'darkModeTutorial';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: Hive.box(darkModeBox).listenable(),
      builder: (context, box, widget) {
        var darkMode = box.get('darkMode', defaultValue: false);
        return MaterialApp(
          themeMode: darkMode ? ThemeMode.dark : ThemeMode.light,
          darkTheme: ThemeData.dark(),
          home: Scaffold(
            body: Center(
              child: Switch(
                value: darkMode,
                onChanged: (val) {
                  box.put('darkMode', !darkMode);
                },
              ),
            ),
          ),
        );
      },
    );
  }
}

实战2 Favorite Books Introduction

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

const favoritesBox = 'favorite_books';
const List<String> books = [
  'Harry Potter',
  'To Kill a Mockingbird',
  'The Hunger Games',
  'The Giver',
  'Brave New World',
  'Unwind',
  'World War Z',
  'The Lord of the Rings',
  'The Hobbit',
  'Moby Dick',
  'War and Peace',
  'Crime and Punishment',
  'The Adventures of Huckleberry Finn',
  'Catch-22',
  'The Sound and the Fury',
  'The Grapes of Wrath',
  'Heart of Darkness',
];

void main() async {
  await Hive.initFlutter();
  await Hive.openBox<String>(favoritesBox);
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Box<String> favoriteBooksBox;

  @override
  void initState() {
    super.initState();
    favoriteBooksBox = Hive.box(favoritesBox);
  }

  Widget getIcon(int index) {
    if (favoriteBooksBox.containsKey(index)) {
      return Icon(Icons.favorite, color: Colors.red);
    }
    return Icon(Icons.favorite_border);
  }

  void onFavoritePress(int index) {
    if (favoriteBooksBox.containsKey(index)) {
      favoriteBooksBox.delete(index);
      return;
    }
    favoriteBooksBox.put(index, books[index]);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Favorite Books',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Favorite Books'),
        ),
        body: ValueListenableBuilder(
          valueListenable: favoriteBooksBox.listenable(),
          builder: (context, Box<String> box, _) {
            return ListView.builder(
              itemCount: books.length,
              itemBuilder: (context, listIndex) {
                return ListTile(
                  title: Text(books[listIndex]),
                  trailing: IconButton(
                    icon: getIcon(listIndex),
                    onPressed: () => onFavoritePress(listIndex),
                  ),
                );
              },
            );
          },
        ),
      ),
    );
  }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Flutter 是一种跨平台的移动应用开发框架,能够快速构建高效、美观的应用程序。下面我将介绍从入门到进阶的学习路径,并给出实战携程网应用程序的资料。 1. 入门阶段: - 学习Dart语言基础:Dart 是 Flutter 的编程语言,掌握其基本语法和特性非常重要。 - 安装Flutter SDK:根据官方指南下载并配置好Flutter开发环境。 - 理解Flutter基础概念:学习Flutter的基本概念,如Widget、State、BuildContext等。 - 创建第一个Flutter应用:通过编写一个简单的计数器应用程序加深对Flutter开发流程的理解。 2. 进阶阶段: - 深入学习Widget:掌握Flutter中的各种Widget,了解它们的层次结构以及常用属性和方法。 - 路由和导航组件:学习如何实现应用程序之间的页面跳转和导航功能。 - 网络请求与数据处理:学习如何使用Flutter的网络请求库,并结合携程网的API接口获取数据。 - 状态管理:掌握不同的状态管理方案,例如Provider、GetX等,以便更好地管理应用程序的复杂状态。 - 自定义控件和动画:学习如何自定义Flutter控件,以及如何使用动画使应用程序更加生动和流畅。 实战携程网app资料: - Flutter官方文档:提供了全面的Flutter开发指南和示例代码,可在Flutter官方网站找到。 - Github上的开源项目:可以在Github上搜索到一些开源的Flutter项目,其中可能包含实现携程网app功能的示例代码。 - 携程网提供的开放API:携程网提供了一些开放接口供开发者使用,可通过API文档了解接口的使用方法,然后在Flutter中进行集成。 通过系统学习和实践,从入门到进阶,您将能够掌握Flutter开发技术,并有能力构建出类似携程网的应用程序。加油!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

wniuniu_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值