求助:Flutter中'String'非'Map<String, dynamic>'子类型的类型错误
解决类型错误:'String' is not a subtype of type 'Map<String, dynamic>'
错误根源
你遇到的类型错误核心原因是Hive存储的数据类型和解析时预期的不匹配:
- 要么你往Hive里存的是JSON字符串,但解析时做了冗余的
jsonEncode+jsonDecode操作,导致最终拿到的还是字符串,无法转成Map; - 要么你没给Hive的Box指定明确泛型类型,用
dynamic导致读取的数据类型不确定。
针对性解决方案
情况1:Hive存储的是JSON字符串
如果之前是把Provider对象转成JSON字符串存到Hive里,按以下步骤修改:
1. 修正LoadData函数
指定Box的泛型为String,明确返回字符串列表:
Future<List<String>> LoadData() async { final box = Hive.box<String>('my_db'); return box.values.toList(); }
2. 修正FutureBuilder解析逻辑
直接对每个字符串做jsonDecode转成Map,再传入Provider.fromJson:
FutureBuilder<List<String>>( future: LoadData(), builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) { if (!snapshot.hasData) { return const Center(child: Text('loading')); } return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (BuildContext context, int index) { // 直接解码JSON字符串为Map final Map<String, dynamic> decodedData = jsonDecode(snapshot.data![index]); final itemData = Provider.fromJson(decodedData); return ListTile( title: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox(width: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( itemData.logo, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 20, color: Colors.green, ), ), const Icon(Icons.more_horiz, color: Colors.blue), ], ), ], ), ); }, ); }, )
情况2:Hive存储的是Map对象(推荐)
如果存储时直接存的是Map,可简化流程,避免字符串解码开销:
1. 存储时的代码参考(如果之前没这么做)
// 示例:往Hive存Map类型数据 final box = Hive.box<Map<String, dynamic>>('my_db'); await box.put('some_key', { 'id': '1', 'network': 'Example Network', 'discount': '10', // 如果是数字可以直接存10,后续解析不用int.parse 'logo': 'Example Logo' });
2. 修正LoadData函数
指定Box的泛型为Map<String, dynamic>:
Future<List<Map<String, dynamic>>> LoadData() async { final box = Hive.box<Map<String, dynamic>>('my_db'); return box.values.toList(); }
3. 修正FutureBuilder解析逻辑
直接将Map传入Provider.fromJson,无需额外解码:
FutureBuilder<List<Map<String, dynamic>>>( future: LoadData(), builder: (BuildContext context, AsyncSnapshot<List<Map<String, dynamic>>> snapshot) { if (!snapshot.hasData) { return const Center(child: Text('loading')); } return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (BuildContext context, int index) { final itemData = Provider.fromJson(snapshot.data![index]); return ListTile( title: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox(width: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Text( itemData.logo, style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 20, color: Colors.green, ), ), const Icon(Icons.more_horiz, color: Colors.blue), ], ), ], ), ); }, ); }, )
额外优化建议
- Provider类的discount解析:如果Hive里存的是数字类型,直接用
data['discount'] as int替代int.parse(data['discount'])更高效;如果存的是字符串,建议加int.tryParse做异常处理避免崩溃。 - 避免dynamic类型:给Hive的Box指定明确泛型类型,能提前发现类型问题,减少运行时错误。
- 完善FutureBuilder状态处理:可以加上
snapshot.hasError的判断,展示错误提示,提升用户体验。
内容的提问来源于stack exchange,提问作者Eniedi Monday
相关产品推荐
相关产品推荐

