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

Flutter调用API时遇Null与String类型不匹配错误求助

问题解决思路

核心问题分析

  1. API返回格式不匹配:目标API返回的是**数组(List)**而非单个对象(Map),但你的代码直接用Squadre.fromJson解析整个响应体,导致类型不匹配;同时数组内部分对象的字段存在null值,与你定义的非空String字段冲突,触发Null is not a subtype of String错误。
  2. 字段非空约束冲突:Squadre类的所有字段都被声明为非空String,但API返回的部分字段(如squ_2allenatore)可能为null,直接赋值会触发类型转换异常。

修正步骤

1. 调整数据模型与解析逻辑

修改Squadre类,将可能为null的字段设为可空类型,并适配API返回的数组格式:

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

// 改为返回List<Squadre>,适配API数组格式
Future<List<Squadre>> fetchSquadre() async {
  final response = await http
      .get(Uri.parse('https://www.bkgchallenge.it/badmin/APIM/getsquadre.php'));

  if (response.statusCode == 200) {
    // 先解析为List,再逐个转换为Squadre对象
    List<dynamic> jsonList = jsonDecode(response.body);
    return jsonList.map((json) => Squadre.fromJson(json)).toList();
  } else {
    throw Exception('Non sono riuscito a decodificare le squadre');
  }
}

class Squadre {
  final String squId;
  final String squNome;
  final String squStagione;
  final String? squ1Allenatore; // 设为可空类型
  final String? squ2Allenatore; // 设为可空类型

  const Squadre({
    required this.squId,
    required this.squNome,
    required this.squStagione,
    this.squ1Allenatore,
    this.squ2Allenatore,
  });

  factory Squadre.fromJson(Map<String, dynamic> json) {
    return Squadre(
      // 为必填字段添加空值兜底,避免null赋值给非空String
      squId: json['squ_id'] ?? '',
      squNome: json['squ_nome'] ?? '',
      squStagione: json['squ_stagione'] ?? '',
      // 可空字段直接接收null
      squ1Allenatore: json['squ_1allenatore'],
      squ2Allenatore: json['squ_2allenatore'],
    );
  }
}

2. 更新UI展示逻辑

因为返回的是列表数据,改用ListView.builder展示所有球队信息,并处理可空字段的显示:

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: QuoteList(),
    );
  }
}

class QuoteList extends StatefulWidget {
  const QuoteList({super.key});

  @override
  State<QuoteList> createState() => _QuoteListState();
}

class _QuoteListState extends State<QuoteList> {
  late Future<List<Squadre>> futureSquadre;

  @override
  void initState() {
    super.initState();
    futureSquadre = fetchSquadre();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Lista'),
        ),
        body: Center(
          child: FutureBuilder<List<Squadre>>(
            future: futureSquadre,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return ListView.builder(
                  itemCount: snapshot.data!.length,
                  itemBuilder: (context, index) {
                    final squadra = snapshot.data![index];
                    return ListTile(
                      title: Text(squadra.squNome),
                      subtitle: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('ID: ${squadra.squId}'),
                          Text('Stagione: ${squadra.squStagione}'),
                          // 对可空字段做null判断,显示兜底文本
                          Text('Allenatore 1: ${squadra.squ1Allenatore ?? 'Nessuno'}'),
                          Text('Allenatore 2: ${squadra.squ2Allenatore ?? 'Nessuno'}'),
                        ],
                      ),
                    );
                  },
                );
              } else if (snapshot.hasError) {
                return Text('${snapshot.error}');
              }

              // 默认显示加载指示器
              return const CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

关键说明

  • 数组解析适配:API返回的是多个球队数据的数组,必须先解析为List<dynamic>,再遍历转换为Squadre对象,不能直接用单个对象的解析方法。
  • 空值安全处理:对于API可能返回null的字段,要么声明为可空类型,要么用??运算符设置兜底值(如空白字符串),避免类型转换异常。
  • UI适配列表数据:用ListView.builder展示列表数据,同时对可空字段做null判断,保证UI渲染时不会因null值报错。

内容的提问来源于stack exchange,提问作者Mauro Ds

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:10:29