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

Flutter启动从Hive加载自定义列表失败:类型转换错误

Hive存储自定义类列表时的类型转换错误问题

自定义Hive实体类

我定义了如下Hive自定义类:

@HiveType(typeId: 1)
class GeocodeLocationGoogleItem {
  @HiveField(0)
  String formattedAddress;
  @HiveField(1)
  String lat;
  @HiveField(2)
  String lng;
  @HiveField(3)
  DateTime lastUpdate;
  @HiveField(4)
  HourlyForcastWeatherbit hourlyForcast;

  GeocodeLocationGoogleItem(this.formattedAddress, this.lat, this.lng,
      this.lastUpdate, this.hourlyForcast);
}

列表存储代码

我通过以下代码存储该类的列表:

void saveLocationsToMemory() async {
    //open box
    var box = await Hive.openBox<List<GeocodeLocationGoogleItem>>('weatherBox');

    //update list to storage
    box.put('weatherLocationList', weatherLocations);
}

初始化与加载流程

应用重启时,我先初始化Hive并注册适配器:

WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(GeocodeLocationGoogleItemAdapter());
Hive.registerAdapter(HourlyForcastWeatherbitAdapter());
Hive.registerAdapter(HourlyDataWeatherbitAdapter());

之后在Widget的initState中调用加载方法:

Provider.of<Settings>(context, listen: false).loadLocationsFromMemory();

错误信息

执行时出现类型转换错误,无法加载列表:

E/flutter (23601): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)]
Unhandled Exception: type 'List' is not a subtype of type 'List?' in type cast
E/flutter (23601): #0 BoxImpl.get (package:hive/src/box/box_impl.dart:44:26)
E/flutter (23601): #1 Settings.loadLocationsFromMemory (package:dont_forget_the_weather/provider/settings_class.dart:66:28)
E/flutter (23601):
E/flutter (23601):

加载方法代码

Settings.loadLocationsFromMemory方法的第66行代码为:

weatherLocations = box.get("weatherLocationList", defaultValue: [])!;

完整方法如下:

void loadLocationsFromMemory() async {
    var box = await Hive.openBox<List<GeocodeLocationGoogleItem>>('weatherBox');

    weatherLocations = box.get("weatherLocationList", defaultValue: [])!;

    notifyListeners();
}

解决方案

问题核心是Hive不支持将泛型列表直接作为Box的类型参数,以下是两种修复方案:

方案1:直接存储实体列表(推荐)

修改存储和加载逻辑,将Box类型指定为实体类本身,通过addAll和values.toList()处理列表:

// 修改存储方法
void saveLocationsToMemory() async {
    var box = await Hive.openBox<GeocodeLocationGoogleItem>('weatherBox');
    await box.clear(); // 清空旧数据
    await box.addAll(weatherLocations);
}

// 修改加载方法
void loadLocationsFromMemory() async {
    var box = await Hive.openBox<GeocodeLocationGoogleItem>('weatherBox');
    weatherLocations = box.values.toList();
    notifyListeners();
}

方案2:保留单键存储逻辑

如果要保留原单键存储方式,去掉Box的泛型指定,获取数据时手动强转类型:

// 修改存储方法
void saveLocationsToMemory() async {
    var box = await Hive.openBox('weatherBox');
    box.put('weatherLocationList', weatherLocations);
}

// 修改加载方法
void loadLocationsFromMemory() async {
    var box = await Hive.openBox('weatherBox');
    var rawList = box.get("weatherLocationList", defaultValue: []);
    weatherLocations = rawList.cast<GeocodeLocationGoogleItem>();
    notifyListeners();
}

注意事项

  • 确保所有嵌套实体类(如HourlyForcastWeatherbit)的适配器已正确注册,否则会序列化失败。
  • 若之前存储过错误格式的数据,建议卸载应用清除旧数据,或在初始化时调用box.delete('weatherLocationList')清理。

内容的提问来源于stack exchange,提问作者Ten Digit Grid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 05:35:20