You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Flutter中使用Hive本地存储CategoryModel列表的方法

解决Hive存储CategoryModel列表失败的问题

一、配置依赖

先确保pubspec.yaml中添加Hive相关依赖:

dependencies:
  flutter:
    sdk: flutter
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: ^2.4.4
  hive_generator: ^1.1.5

二、处理自定义类的序列化

Hive无法直接存储自定义对象和特殊类型(如File、IconData、Color等),需要通过注解生成适配器,并将特殊类型转换为可序列化的基础类型:

1. 处理枚举类(CategoryType)

如果CategoryType是枚举,添加Hive注解标记:

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

@HiveType(typeId: 0)
enum CategoryType {
  @HiveField(0)
  type1,
  @HiveField(1)
  type2,
  // 补充你的实际枚举项
}

2. 处理ListTileData(自定义类)

如果ListTileData是你定义的类,同样需要添加Hive注解:

@HiveType(typeId: 1)
class ListTileData {
  @HiveField(0)
  final String title;
  // 补充你的其他字段

  ListTileData({required this.title});
}

3. 修改CategoryModel类

将特殊类型转换为可序列化的基础类型,添加Hive注解:

@HiveType(typeId: 2)
class CategoryModel {
  CategoryModel({
    required this.type,
    IconData? iconData,
    List<File>? imageList,
    this.notesText,
    IconData? reminderIcon,
    this.reminderText,
    this.reminderTimeText,
    this.titel,
    Color? color,
    this.rawList,
    this.reminderwidth,
    this.backgroundImage,
    Color? reminderColor,
    this.selectedTile,
    this.selectedimage,
    this.path,
    this.crossCount,
    Duration? duration,
    this.colorSelected,
    this.isSelected = false,
    this.checkScreen = false,
    this.notesController,
  }) {
    // 初始化特殊类型的转换字段
    this.iconData = iconData;
    this.imageList = imageList;
    this.reminderIcon = reminderIcon;
    this.color = color;
    this.reminderColor = reminderColor;
    this.duration = duration;
  }

  @HiveField(0)
  final CategoryType type;

  @HiveField(1)
  String? titel;

  // IconData 转换存储:存codePoint和fontFamily
  @HiveField(2)
  int? _iconDataCodePoint;
  @HiveField(3)
  String? _iconDataFontFamily;
  IconData? get iconData {
    if (_iconDataCodePoint == null || _iconDataFontFamily == null) return null;
    return IconData(_iconDataCodePoint!, fontFamily: _iconDataFontFamily);
  }
  set iconData(IconData? value) {
    _iconDataCodePoint = value?.codePoint;
    _iconDataFontFamily = value?.fontFamily;
  }

  @HiveField(4)
  String? notesText;

  // List<File> 转换存储:存文件路径列表
  @HiveField(5)
  List<String>? _imagePaths;
  List<File>? get imageList {
    if (_imagePaths == null) return null;
    return _imagePaths!.map((path) => File(path)).toList();
  }
  set imageList(List<File>? value) {
    _imagePaths = value?.map((file) => file.path).toList();
  }

  // ReminderIcon 同IconData处理
  @HiveField(6)
  int? _reminderIconCodePoint;
  @HiveField(7)
  String? _reminderIconFontFamily;
  IconData? get reminderIcon {
    if (_reminderIconCodePoint == null || _reminderIconFontFamily == null) return null;
    return IconData(_reminderIconCodePoint!, fontFamily: _reminderIconFontFamily);
  }
  set reminderIcon(IconData? value) {
    _reminderIconCodePoint = value?.codePoint;
    _reminderIconFontFamily = value?.fontFamily;
  }

  @HiveField(8)
  String? reminderText;

  @HiveField(9)
  String? reminderTimeText;

  // Color 转换存储:存颜色的int值
  @HiveField(10)
  int? _colorValue;
  Color? get color {
    if (_colorValue == null) return null;
    return Color(_colorValue!);
  }
  set color(Color? value) {
    _colorValue = value?.value;
  }

  @HiveField(11)
  List<ListTileData>? rawList;

  @HiveField(12)
  double? reminderwidth;

  @HiveField(13)
  String? backgroundImage;

  // ReminderColor 同Color处理
  @HiveField(14)
  int? _reminderColorValue;
  Color? get reminderColor {
    if (_reminderColorValue == null) return null;
    return Color(_reminderColorValue!);
  }
  set reminderColor(Color? value) {
    _reminderColorValue = value?.value;
  }

  @HiveField(15)
  int? selectedTile;

  @HiveField(16)
  int? selectedimage;

  @HiveField(17)
  bool? checkScreen;

  @HiveField(18)
  String? notesController;

  @HiveField(19)
  int? crossCount;

  @HiveField(20)
  String? path;

  // Duration 转换存储:存毫秒数
  @HiveField(21)
  int? _durationMilliseconds;
  Duration? get duration {
    if (_durationMilliseconds == null) return null;
    return Duration(milliseconds: _durationMilliseconds!);
  }
  set duration(Duration? value) {
    _durationMilliseconds = value?.inMilliseconds;
  }

  @HiveField(22)
  int? colorSelected;

  @HiveField(23)
  bool? isSelected;
}

三、生成适配器

在项目根目录的终端运行以下命令,生成所有自定义类的Hive适配器:

flutter packages pub run build_runner build

四、初始化Hive并注册适配器

在main函数中初始化Hive,注册所有适配器并打开存储box:

import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'path/to/your/model/file.dart'; // 替换为你的CategoryModel文件路径

void main() async {
  await Hive.initFlutter();
  // 注册所有适配器
  Hive.registerAdapter(CategoryModelAdapter());
  Hive.registerAdapter(CategoryTypeAdapter());
  Hive.registerAdapter(ListTileDataAdapter());
  // 打开存储CategoryModel的box
  await Hive.openBox<CategoryModel>('categories_box');
  runApp(const MyApp());
}

五、存储和读取数据

现在可以正常存储和读取allCategory列表了:

// 获取存储box
final categoriesBox = Hive.box<CategoryModel>('categories_box');

// 存储allCategory列表
await categoriesBox.clear(); // 可选,清空旧数据
await categoriesBox.addAll(allCategory);

// 读取存储的列表
List<CategoryModel> storedCategories = categoriesBox.values.toList();

常见问题排查

  • 未注册适配器:打开box前必须注册所有自定义类的Adapter,否则会报错
  • 特殊类型未处理:Hive仅支持基础类型、List/Map和Hive注解的自定义类,像File、IconData这类必须转换为可序列化类型
  • TypeId冲突:每个@HiveType的typeId必须唯一,不能与其他类重复
  • 字段未加@HiveField:所有需要存储的字段必须添加@HiveField注解,且index不能重复

内容的提问来源于stack exchange,提问作者Satvik Donda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 19:12:18