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

Flutter从Hive读取数据时触发JSON解析错误:Unexpected character的修复方案咨询

Flutter从Hive读取数据时触发JSON解析错误:Unexpected character的修复方案咨询

Hey,我来帮你分析下这个问题的根源,然后给出两种解决办法:

错误原因解析

你遇到的Unexpected character错误,是因为你在尝试用jsonDecode解析一个非标准JSON格式的字符串。你打印出来的{id: 2, network: MTN, discount: 2, logo: mtncard.png}其实是Dart中Map对象的字符串表示,而不是符合规范的JSON(JSON要求所有键必须用双引号包裹,比如{"id": "2", "network": "MTN"...}),所以jsonDecode自然会报错。

解决方案一:快速修复(直接使用Hive读取的Map对象)

既然你之前是把Map类型的数据存入Hive的,那读取出来的本身就是Map对象,根本不需要用jsonDecode去解析。直接修改你FutureBuilder里的代码即可:

// 去掉原来的jsonDecode行,直接转换类型
final Map<String, dynamic> decodedData = snapshot.data[index] as Map<String, dynamic>;
final itemData = Provider.fromJson(decodedData);

这样就能跳过错误的JSON解析步骤,直接用你已经写好的fromJson方法把Map转成Provider对象。

解决方案二:推荐方案(使用Hive TypeAdapter存储自定义对象)

上面的方法只是临时修复,更规范的做法是让Hive直接存储和读取你的Provider自定义对象,不需要手动处理Map和JSON的转换,步骤如下:

  1. 添加依赖
    在pubspec.yaml里补充Hive相关的开发依赖:
dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  build_runner: ^2.1.7
  hive_generator: ^1.1.5
  1. 修改Provider类,添加Hive注解
    给你的Provider类加上Hive的序列化注解,并生成对应的Adapter:
import 'package:hive/hive.dart';

// 这行是用来指定生成的Adapter文件,后面会自动生成
part 'provider.g.dart';

// 每个自定义类型需要唯一的typeId,这里用0即可
@HiveType(typeId: 0)
class Provider {
  // 每个字段用HiveField标记,索引从0开始递增
  @HiveField(0)
  final String id;
  @HiveField(1)
  final String network;
  @HiveField(2)
  final int discount;
  @HiveField(3)
  final String logo;

  Provider({
    required this.id,
    required this.network,
    required this.discount,
    required this.logo,
  });
}
  1. 生成TypeAdapter文件
    在终端运行以下命令,自动生成provider.g.dart文件:
flutter packages pub run build_runner build
  1. 在main函数中注册Adapter
    初始化Hive的时候注册生成的Adapter:
import 'package:hive_flutter/hive_flutter.dart';
import 'provider.dart'; // 导入你的Provider类

void main() async {
  await Hive.initFlutter();
  // 注册生成的ProviderAdapter
  Hive.registerAdapter(ProviderAdapter());
  // 打开专门存储Provider类型的box
  await Hive.openBox<Provider>('my_db');
  runApp(MyApp());
}
  1. 修改存储和读取逻辑
  • 存储的时候直接存Provider对象:
final box = Hive.box<Provider>('my_db');
await box.add(Provider(id: "2", network: "MTN", discount: 2, logo: "mtncard.png"));
  • 修改读取数据的函数:
Future<List<Provider>> LoadData() async {
  final box = Hive.box<Provider>('my_db');
  return box.values.toList();
}
  • 最后修改FutureBuilder,直接使用读取到的Provider对象:
FutureBuilder<List<Provider>>(
  future: LoadData(),
  builder: (BuildContext context, AsyncSnapshot<List<Provider>> snapshot) {
    if (!snapshot.hasData) {
      return const Center(child: Text('loading'));
    } else {
      return ListView.builder(
        itemCount: snapshot.data!.length,
        itemBuilder: (BuildContext context, int index) {
          // 直接获取Provider对象,无需转换
          final itemData = snapshot.data![index];
          return ListTile(
            title: Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                const SizedBox(width: 20),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    Text(
                      itemData.discount.toString(),
                      style: const TextStyle(
                        fontWeight: FontWeight.bold,
                        fontSize: 20,
                        color: Colors.green,
                      ),
                    ),
                    const Icon(Icons.more_horiz, color: Colors.blue),
                  ],
                ),
              ],
            ),
          );
        },
      );
    }
  },
),

这种方法不仅能彻底解决你的解析错误,还能让数据存储和读取的逻辑更清晰、更安全,避免手动类型转换带来的潜在问题。

备注:内容来源于stack exchange,提问作者Monday P Godstime

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 12:14:32