Hive本地存储报错:Null无法转为String,应用重启崩溃
问题分析与解决方案
一、核心错误根源与修复
1. type 'Null' is not a subtype of type 'String' in type cast(Hive相关崩溃)
这个错误是因为从Hive读取数据时,AddressModel的某个字段为null,但模型定义了非空String,导致类型转换失败;加上main函数重复打开Hive盒子的操作,加剧了初始化冲突。
修复步骤:
- 删除重复打开Hive盒子的代码:
你已经通过Future.wait批量打开了三个盒子,后续的if (!Hive.isBoxOpen(...))判断完全多余,甚至会引发重复打开的异常。直接删除以下代码:// 删掉这段重复打开逻辑 if (!Hive.isBoxOpen('products')) { await Hive.openBox<ProductModel>('products'); } if (!Hive.isBoxOpen('schedule')) { await Hive.openBox<ScheduleModel>('schedule'); } if (!Hive.isBoxOpen('address')) { await Hive.openBox<AddressModel>('address'); } - 处理AddressModel的空安全:
若无法保证写入Hive的所有字段都不为null,建议将模型字段改为可空类型,或添加默认值:
若需兼容旧数据,可给Hive添加迁移逻辑,确保读取旧数据时自动填充默认值。@HiveType(typeId: 2) class AddressModel extends HiveObject { @HiveField(0) String? addtype; // 改为可空类型 @HiveField(1) String? houseno; @HiveField(2) String? buildingname; @HiveField(3) String? area; @HiveField(4) String? landmark; @HiveField(5) String? city; @HiveField(6) String? state; @HiveField(7) String? latitude; @HiveField(8) String? longitude; AddressModel({ this.addtype, this.houseno, this.buildingname, this.area, this.landmark, this.city, this.state, this.latitude, this.longitude, }); // 可选:保留非空约束,添加带默认值的构造函数 AddressModel.withDefaults() : addtype = "", houseno = "", buildingname = "", area = "", landmark = "", city = "", state = "", latitude = "", longitude = ""; }
2. type 'PlatformException' is not a subtype of type 'String?'(地理编码相关崩溃)
这个错误出现在_getAddressFromLatLng方法中,根源是空安全处理不到位+异常处理逻辑错误。
修复步骤:
- 用方法参数
position替代_currentPosition!:
方法已传入position,却强制解包_currentPosition,若_currentPosition为null会直接崩溃。修改如下:await placemarkFromCoordinates( position.latitude, // 直接用参数position position.longitude ) - 判断placemarks列表是否为空:
地理编码可能返回空列表,直接取placemarks[0]会报错,先做判断:.then((List<Placemark> placemarks) async { if (placemarks.isEmpty) { debugPrint("未匹配到地址信息"); return; } Placemark place = placemarks[0]; // 后续逻辑... }) - 处理Placemark字段的null情况:
Placemark的locality、postalCode等字段可能为null,直接存toString()会得到"null"字符串,建议用空字符串替代:city = place.locality ?? ""; statename = place.administrativeArea ?? ""; pincode = place.postalCode ?? ""; area = place.subLocality ?? ""; SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setString("city", city); prefs.setString("pincode", pincode); prefs.setString("area", area); prefs.setString("statename", statename); prefs.setString("country", place.country ?? ""); - 正确处理异常类型:
placemarkFromCoordinates抛出的是PlatformException,直接debugPrint(e)可能引发类型转换问题,明确异常类型后处理:.catchError((e) { if (e is PlatformException) { debugPrint("地理编码错误: ${e.message ?? "未知错误"}"); } else { debugPrint("未知错误: $e"); } });
二、额外优化建议
- FCM Token空值处理:
fcmToken可能为null,直接toString()会存入"null"字符串,建议先判断:String? fcmToken = await messaging.getToken(); if (fcmToken != null) { await prefs.setString("fcmToken", fcmToken); } else { debugPrint("获取FCM Token失败"); }
内容的提问来源于stack exchange,提问作者Swapnil Mane
相关产品推荐
相关产品推荐

