flutter数据保存实体之Hive(二--复杂数据结构)

在 Flutter 中使用 Hive 处理复杂数据结构(如嵌套对象、集合、继承、多态等)时,需要结合 Hive 的类型适配器(TypeAdapter)和灵活的数据建模策略。

一、处理复杂数据结构的核心思路

  • 分解嵌套对象:将复杂对象拆解为多个可序列化的子对象。

  • 注册多适配器:为每个子类型单独生成适配器。

  • 利用泛型与组合:通过组合模式或泛型适配器处理动态类型。

  • 数据版本管理:处理数据结构变更时的兼容性。


二、常见复杂场景与解决方案

  • 嵌套对象
    假设有一个 User 类,包含 Address 嵌套对象:
// address.dart
@HiveType(typeId: 1)
class Address {
  @HiveField(0)
  final String city;

  @HiveField(1)
  final String street;

  Address(this.city, this.street);
}

// user.dart
@HiveType(typeId: 0)
class User {
  @HiveField(0)
  final String name;

  @HiveField(1)
  final Address address; // 嵌套对象

  User(this.name, this.address);
}

步骤:

  • 为 User 和 Address 分别生成适配器:
flutter pub run build_runner build
  • 注册所有适配器:
void main() async {
  await Hive.initFlutter();
  Hive.registerAdapter(UserAdapter());
  Hive.registerAdapter(AddressAdapter());
  runApp(MyApp());
}

  1. 集合类型(List/Map)
  • 存储包含集合的对象(如用户有多个订单):
@HiveType(typeId: 2)
class Order {
  @HiveField(0)
  final String id;

  @HiveField(1)
  final double amount;

  Order(this.id, this.amount);
}

@HiveType(typeId: 3)
class UserWithOrders {
  @HiveField(0)
  final String name;

  @HiveField(1)
  final List<Order> orders; // 列表嵌套

  UserWithOrders(this.name, this.orders);
}
  • 适配器注册:
Hive.registerAdapter(OrderAdapter());
Hive.registerAdapter(UserWithOrdersAdapter());

  • . 继承与多态
    处理父类和子类的序列化(如 Animal 和 Cat/Dog):
// 父类
@HiveType(typeId: 4)
abstract class Animal {
  @HiveField(0)
  final String name;

  Animal(this.name);
}

// 子类 Cat
@HiveType(typeId: 5)
class Cat extends Animal {
  @HiveField(1)
  final int lives;

  Cat(String name, this.lives) : super(name);
}

// 子类 Dog
@HiveType(typeId: 6)
class Dog extends Animal {
  @HiveField(1)
  final String breed;

  Dog(String name, this.breed) : super(name);
}
  • 注册适配器:
Hive.registerAdapter(AnimalAdapter());
Hive.registerAdapter(CatAdapter());
Hive.registerAdapter(DogAdapter());
  • 使用多态存储:
final animalsBox = await Hive.openBox<Animal>('animals');
animalsBox.add(Cat('Whiskers', 9));
animalsBox.add(Dog('Buddy', 'Golden Retriever'));

三、封装通用工具类(支持复杂结构)
扩展之前的 HiveHelper,增强对复杂数据结构的支持:

import 'package:hive/hive.dart';

class HiveHelper<T> {
  final String boxName;
  Box<T>? _box;

  HiveHelper({required this.boxName});

  Future<void> init() async {
    _box = await Hive.openBox<T>(boxName);
  }

  // 支持批量操作
  Future<void> putAll(Map<String, T> entries) async {
    await _box?.putAll(entries);
  }

  // 支持条件查询
  List<T> where(bool Function(T item) test) {
    return _box?.values.where(test).toList() ?? [];
  }

  // 处理嵌套对象的保存(如 List<Order>)
  Future<void> addNestedList<TItem>(
    String parentKey,
    List<TItem> items, {
    required String Function(TItem) itemKeyGenerator,
  }) async {
    final parent = _box?.get(parentKey);
    if (parent != null && parent is List) {
      parent.addAll(items);
      await _box?.put(parentKey, parent);
    }
  }

  // 数据迁移支持
  Future<void> migrateData<TNew>(
    String newBoxName,
    TNew Function(T old) converter,
  ) async {
    final newBox = await Hive.openBox<TNew>(newBoxName);
    final oldData = getAll();
    for (var item in oldData) {
      newBox.add(converter(item));
    }
    await clear();
  }

  // 其他基础方法(同之前)
  // ...
}

四、实战示例:存储复杂用户数据
假设需要存储包含多个地址和订单的用户:

// 定义复杂实体类
@HiveType(typeId: 7)
class ComplexUser {
  @HiveField(0)
  final String id;

  @HiveField(1)
  final List<Address> addresses;

  @HiveField(2)
  final Map<String, Order> orders;

  ComplexUser(this.id, this.addresses, this.orders);
}

// 生成适配器后使用工具类
final userHelper = HiveHelper<ComplexUser>(boxName: 'complexUsers');
await userHelper.init();

// 存储数据
final user = ComplexUser(
  'user_123',
  [Address('New York', '5th Ave'), Address('London', 'Baker St')],
  {
    'order_1': Order('order_1', 99.9),
    'order_2': Order('order_2', 149.9),
  },
);
await userHelper.put(user.id, user);

// 查询所有纽约的用户
final nyUsers = userHelper.where((user) => 
  user.addresses.any((addr) => addr.city == 'New York')
);

五、高级技巧与注意事项

  • 性能优化:

对大型集合使用 HiveList(延迟加载)。

分页加载数据,避免一次性读取全部内容。

  • 数据加密:
final key = Hive.generateSecureKey();
final encryptedBox = await Hive.openBox(
  'secureBox',
  encryptionCipher: HiveAesCipher(key),
);

数据版本管理:

@HiveType(typeId: 8)
class MyData {
  @HiveField(0, defaultValue: 'Unknown')
  String name; // 新增字段时设置默认值
}

调试复杂结构:

  • 使用 Hive.openBox('myBox').toMap() 导出所有数据检查。

  • 结合 jsonEncode() 将对象转换为 JSON 字符串查看结构。


六、常见问题解决

  • 适配器未注册:

  • 确保所有嵌套类型的适配器已注册。

  • 检查 typeId 是否全局唯一。

  • 数据迁移失败:

  • 使用 @HiveField 的 defaultValue 处理新增字段。

  • 通过 migration 参数手动迁移旧数据。

  • 性能瓶颈:

  • 避免频繁写入小数据,合并操作为批量写入。

  • 对大型数据集使用 LazyBox。


通过以上方法,可以高效处理 Flutter 中的复杂数据结构,结合 Hive 的高性能和类型安全特性,满足从简单配置到复杂业务数据的存储需求。


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容