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

Flutter解析本地数据库JSON数据失败,报错‘An error has occurred!’

Flutter JSON解析失败排查与解决

问题场景

在Flutter项目中尝试从本地数据库接口获取数据并解析JSON:通过fetchInstitute方法请求接口,使用compute函数在独立isolate中调用parseInstitute方法将返回的JSON转换为Institute列表,但运行时界面显示“An error has occurred!”。

相关代码

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<List<Institute>> fetchInstitute(http.Client client) async {
  final response = await client
      .get(Uri.parse('http://192.168.1.5/tkydatabase/fun/anem.php'));

  // Use the compute function to run parseInstitute in a separate isolate.
  return compute(parseInstitute, response.body);
}

List<Institute> parseInstitute(String responseBody) {
  final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();

  return parsed.map<Institute>((json) => Institute.fromJson(json)).toList();
}

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const appTitle = 'Isolate Demo';

    return const MaterialApp(
      title: appTitle,
      home: MyHomePage(title: appTitle),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: FutureBuilder<List<Institute>>(
        future: fetchInstitute(http.Client()),
        builder: (context, snapshot) {
          if (snapshot.hasError) {
            return const Center(
              child: Text('An error has occurred!'),
            );
          } else if (snapshot.hasData) {
            return InstitutesList(institute: snapshot.data!);
          } else {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }
}

class InstitutesList extends StatelessWidget {
  const InstitutesList({super.key, required this.institute});

  final List<Institute> institute;

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemCount: institute.length,
      itemBuilder: (context, index) {
        return Text(institute[index].instituteName);
      },
    );
  }
}

// 假设的Institute模型类(需确认实际实现)
class Institute {
  final String instituteName;

  Institute({required this.instituteName});

  factory Institute.fromJson(Map<String, dynamic> json) {
    return Institute(
      instituteName: json['instituteName'],
    );
  }
}

排查与解决步骤

1. 先获取具体错误信息

当前错误提示过于通用,修改FutureBuilder的错误处理逻辑,打印具体错误内容:

if (snapshot.hasError) {
  return Center(
    child: Text('错误详情: ${snapshot.error}'),
  );
}

运行后即可看到具体报错(比如类型转换错误、字段不存在、JSON格式错误等),针对性解决。

2. 检查接口返回的JSON格式

常见问题:接口返回的不是直接的数组,而是包含数组的对象(例如{"code":200,"data":[{"institute_name":"xxx"},...]})。此时直接jsonDecode(responseBody).cast<Map<String, dynamic>>()会报错,需先取出数组部分:

List<Institute> parseInstitute(String responseBody) {
  final data = jsonDecode(responseBody)['data']; // 根据实际字段名调整
  if (data == null) throw Exception('接口返回数据格式错误');
  
  final parsed = data.cast<Map<String, dynamic>>();
  return parsed.map<Institute>((json) => Institute.fromJson(json)).toList();
}

3. 校验Institute.fromJson实现

  • 确保字段名与接口返回的JSON字段完全匹配(注意大小写、下划线/驼峰差异,例如接口返回institute_name,模型里不能直接用instituteName,需手动映射):
factory Institute.fromJson(Map<String, dynamic> json) {
  return Institute(
    instituteName: json['institute_name'] ?? '', // 加默认值避免空值报错
  );
}
  • 处理空值:如果接口可能返回null字段,需添加默认值或非空判断,避免类型转换异常。

4. 检查网络请求合法性

  • 确认设备与服务器处于同一局域网,192.168.1.5可正常访问。
  • 在fetchInstitute中添加状态码校验,排除请求失败的情况:
Future<List<Institute>> fetchInstitute(http.Client client) async {
  final response = await client
      .get(Uri.parse('http://192.168.1.5/tkydatabase/fun/anem.php'));

  if (response.statusCode != 200) {
    throw Exception('请求失败,状态码: ${response.statusCode}');
  }

  return compute(parseInstitute, response.body);
}

5. 确认parseInstitute的函数类型

compute要求传入的函数是顶级函数或静态函数,当前代码中parseInstitute是顶级函数,符合要求;如果后续将其移入类中,需改为static方法。


内容的提问来源于stack exchange,提问作者Ayoub Benameur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 00:30:44