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

Flutter中通过API调用嵌套JSON数据及解析报错求助

解决Flutter解析嵌套JSON时的「List无法赋值给String」错误

嘿,我看你在解析嵌套JSON的时候碰到了这个类型错误,这个问题其实挺常见的,大多是因为数据类型在某个环节没对应上,咱们一步步来排查和解决:

先搞清楚错误根源

The argument type 'List' can't be assigned to the parameter type 'String'这个错误,本质是你把一个List类型的数据,传给了需要String类型的参数——大概率是在API解析完成后,UI展示或者数据传递的时候出了问题,咱们先从核心的解析流程和实体类开始检查。

1. 优化你的实体类代码

你的实体类整体逻辑是对的,但有几个小细节可以调整,避免后续踩坑:

  • 初始化List的时候,建议用更简洁的map写法替代forEach,不仅代码更紧凑,还能避免手动初始化List时可能出现的问题:
// 修改Album.fromJson的解析逻辑
Album.fromJson(Map<String, dynamic> json) {
  info = (json['Info'] as List).map((v) => Info.fromJson(v)).toList();
}

如果坚持用forEach,记得显式声明List为可增长类型:

info = List<Info>.empty(growable: true);
json['Info'].forEach((v) {
  info.add(Info.fromJson(v));
});

2. 检查API请求与解析的完整流程

确保你发起请求后,正确把响应体转成JSON再实例化Album对象,比如正确的请求流程应该是这样的:

Future<Album> fetchCleaningTypes() async {
  final response = await http.get(Uri.parse('你的API接口地址'));

  if (response.statusCode == 200) {
    // 正确解析JSON为Album实体
    return Album.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('加载清洁类型失败');
  }
}

如果你在这里不小心把jsonDecode(response.body)直接当成String用,或者传给了需要String的参数,就会触发错误。

3. 排查UI展示时的错误(最可能的原因)

如果解析流程和实体类都没问题,那错误十有八九出在UI层——比如你可能直接把album.info(一个List<Info>)传给了需要String的Widget,比如Text():

// ❌ 错误示例:把List直接传给Text
Text(album.info) 

正确的做法是遍历这个List,逐个展示每个Info的内容,比如用ListView:

// ✅ 正确示例:遍历List展示内容
ListView.builder(
  itemCount: album.info.length,
  itemBuilder: (context, index) {
    final cleaningItem = album.info[index];
    return ListTile(
      title: Text(cleaningItem.cleaningType),
      subtitle: Text('ID: ${cleaningItem.cTypeId}'),
    );
  },
)

完整的可运行示例

这里给你一个包含请求、解析、UI展示的完整代码,你可以直接参考:

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

class Album {
  List<Info> info;
  Album({this.info});

  Album.fromJson(Map<String, dynamic> json) {
    info = (json['Info'] as List).map((v) => Info.fromJson(v)).toList();
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    if (info != null) {
      data['Info'] = info.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Info {
  String cTypeId;
  String cleaningType;
  Info({this.cTypeId, this.cleaningType});

  Info.fromJson(Map<String, dynamic> json) {
    cTypeId = json['c_type_id'];
    cleaningType = json['cleaning type'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = Map<String, dynamic>();
    data['c_type_id'] = cTypeId;
    data['cleaning type'] = cleaningType;
    return data;
  }
}

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

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late Future<Album> futureCleaningTypes;

  @override
  void initState() {
    super.initState();
    futureCleaningTypes = fetchCleaningTypes();
  }

  Future<Album> fetchCleaningTypes() async {
    // 替换成你的真实API地址,或者用模拟数据测试
    final response = await http.get(Uri.parse('https://your-api-url.com/cleaning-types'));

    if (response.statusCode == 200) {
      return Album.fromJson(jsonDecode(response.body));
    } else {
      throw Exception('加载清洁类型失败,请稍后重试');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '清洁类型列表',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: Scaffold(
        appBar: AppBar(title: const Text('清洁类型')),
        body: Center(
          child: FutureBuilder<Album>(
            future: futureCleaningTypes,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return ListView.builder(
                  padding: const EdgeInsets.all(16),
                  itemCount: snapshot.data!.info.length,
                  itemBuilder: (context, index) {
                    final item = snapshot.data!.info[index];
                    return Card(
                      margin: const EdgeInsets.only(bottom: 12),
                      child: Padding(
                        padding: const EdgeInsets.all(16),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(item.cleaningType, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
                            const SizedBox(height: 8),
                            Text('类型ID: ${item.cTypeId}'),
                          ],
                        ),
                      ),
                    );
                  },
                );
              } else if (snapshot.hasError) {
                return Text('出错了: ${snapshot.error}');
              }
              // 加载中状态
              return const CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

最后总结一下

你遇到的错误核心就是List类型和String类型的不匹配,优先检查这几个点:

  1. API解析后是否正确得到了Album对象,而不是直接处理原始的List
  2. UI层有没有把List直接传给需要String的Widget(比如Text)
  3. 实体类中List的初始化是否正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 04:49:08