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

求助: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:55:12