Flutter启动从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

