错误:List<dynamic> 在获取 JSON 时不是 Map<String, dynamic> 类型的子类型

Posted

技术标签:

【中文标题】错误:List<dynamic> 在获取 JSON 时不是 Map<String, dynamic> 类型的子类型【英文标题】:Error: List<dynamic> is not a subtype of type Map<String, dynamic> while fetching JSON 【发布时间】:2020-06-27 16:07:40 【问题描述】:

我正在使用 Flutter 构建一个事件应用程序,该应用程序从 Rails api 获取数据并显示其详细信息。 我得到了和this question一样的错误,并且已经尝试了“kapsid”的答案,但还不能解决。


我的模型类(evento.dart)。基本上它代表一个较大的事件,其中包含多个小事件。

import 'package:flutter/material.dart';    

class Evento 
  int id;
  String titulo, descricao, inicio, fim, dataFimInscricao;
  List<Evento> children;

  Evento(
      this.id,
      this.titulo,
      this.descricao,
      this.inicio,
      this.fim,
      this.dataFimInscricao,
      this.children);

  factory Evento.fromJson(Map<String, dynamic> json) 
    var list = json['children'] as List;
    List<Evento> childrenList = list.map((c) => Evento.fromJson(c)).toList();

    return new Evento(
      id: json['id'],
      titulo: json['titulo'],
      descricao: json['descricao'],
      inicio: json['inicio'],
      fim: json['fim'],
      dataFimInscricao: json['data_fim_inscricao'],
      children: childrenList
    );
  

main.dart 列出各种类似的大事件

import 'dart:convert';

import 'package:eventos_app/detalhesEvento.dart';
import 'package:eventos_app/model/evento.dart';
import 'package:eventos_app/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

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

class MyApp extends StatefulWidget 
  @override
  _MyAppState createState() => _MyAppState();


class _MyAppState extends State<MyApp> 
  Future<Evento> futureEvento;

  @override
  void initState() 
    super.initState();
    futureEvento = fetchEvento();
  

  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: FutureBuilder(
          future: futureEvento,
          builder: (context, snapshot) 
            if (!snapshot.hasData) 
              print(snapshot.error);
              return Padding(
                padding: EdgeInsets.all(16),
                child: Center(
                  child: Text(snapshot.error.toString()),
                ),
              );
             else 
              var eventos = json.decode(snapshot.data.toString());

              return ListView.builder(
                itemCount: eventos.length,
                itemBuilder: (BuildContext context, int index) 
                  return Card(
                    margin: EdgeInsets.all(8),
                    elevation: 5,
                    child: ListTile(
                      contentPadding: EdgeInsets.all(8),
                      leading: Icon(
                        Icons.local_florist,
                        size: 35,
                      ),
                      title: Text(eventos[index]['titulo']),
                      subtitle: Text(
                          'Data: $parseDate(eventos[index]['inicio'])\n$eventos[index]['endereco']'),
                      onTap: () 
                        var evento = Evento.fromJson(eventos[index]);
                        print(evento.titulo);
                        Navigator.push(
                            context,
                            MaterialPageRoute(
                                builder: (context) =>
                                    DetalhesEvento(evento: evento)));

                        // Scaffold.of(context).showSnackBar(SnackBar(
                        //   content: Text('$event.title tapped!'),
                        //   duration: new Duration(seconds: 1)
                        // ));
                      ,
                    ),
                  );
                ,
              );
             // else
          ,
        ),
      ),
    );
  


Future<Evento> fetchEvento() async 
  final response =
      await http.get('https://api.myjson.com/bins/1d8142');

  print('----------------------------------------\n');
  print(response.body);
  print('\n----------------------------------------');

  if (response.statusCode == 200) 
    // If the server did return a 200 OK response,
    // then parse the JSON.
//    return Evento.fromJson2(json.decode(response.body));
    return Evento.fromJson(json.decode(response.body));
   else 
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load events');
  

这是示例 JSON

[
  
    "id": 1,
    "titulo": "MAIN EVENT",
    "descricao": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In elementum metus erat. Morbi sit amet pellentesque elit. Sed at gravida nisi. In in diam in mi gravida iaculis. Phasellus ac leo vel arcu faucibus porta at nec elit. Proin imperdiet leo congue, mattis nunc non, laoreet turpis. Morbi sed faucibus lorem.",
    "inicio": "2020-03-13T10:00:00.000-03:00",
    "fim": "2020-03-31T23:59:00.000-03:00",
    "data_fim_inscricao": "2020-03-31T23:59:00.000-03:00",
    "children": [
      
        "id": 4,
        "titulo": "SECONDARY EVENT AAA",
        "descricao": "AAAAA",
        "inicio": "2020-03-24T08:00:00.000-03:00",
        "fim": "2020-03-25T18:00:00.000-03:00",
        "data_fim_inscricao": "2020-03-23T08:00:00.000-03:00",
        "children": [

        ]
      ,
      
        "id": 3,
        "titulo": "SECONDARY EVENT BBB",
        "descricao": "BBBBB",
        "inicio": "2020-03-13T23:59:00.000-03:00",
        "fim": "2020-03-25T23:59:00.000-03:00",
        "data_fim_inscricao": "2020-03-13T23:59:00.000-03:00",
        "children": [

        ]
      ,
      
        "id": 2,
        "titulo": "SECONDARY EVENT CCC",
        "descricao": "CCCCC",
        "inicio": "2020-03-14T10:00:00.000-03:00",
        "fim": "2020-03-16T23:59:00.000-03:00",
        "data_fim_inscricao": "2020-03-16T23:59:00.000-03:00",
        "children": [

        ]
      
    ]
  
]

我做错了什么??

【问题讨论】:

这看起来像是 api 返回的内容和您想要放置的位置之间的数据类型不匹配。我认为用户@Dhiraj Sharma 对如何解决问题有更好的想法。添加开始解决此问题的好方法是将 .runtimetype 添加到您的变量中。 (您可以在此处查看一些示例:***.com/questions/7715948/…)相信我,这不会是您最后一次看到此错误消息。在使用强类型语言进行编码时,这很常见。当你有 print(response.runtimetype) 时你会看到什么? @WilliamTerrill print(response.runtimeType) = 响应;打印(response.body.runtimeType)=字符串; print(jsonDecode(response.body).runtimeType) = List 【参考方案1】:

问题是您收到的数据与预期的数据接收方式不匹配。具体来说,您正在尝试将类型为 List&lt;dynamic&gt; 的 response.body 传递给正在寻找 Map&lt;String, dynamic&gt; 的函数

我无法运行您的代码,但问题似乎出现在 FetchEvento 中的这一行:

return Evento.fromJson(json.decode(response.body)); // <-- you're passing List<dynamic>

因为您正在将类型为 List&lt;dynamic&gt; 的 response.body 传递给 Evento.fromJson(),它需要一个类型为 Map&lt;String,dynamic&gt; 的变量

factory Evento.fromJson(Map<String, dynamic> json)   //<-- you defined json as Map<String,dynamic>

因为 dart 是一种强类型语言,所以必须将它们定义为相同的类型。

最简单的解决方案是以下三件事之一: 1. 最简单的方法是将接收到的变量类型更改为:

factory Evento.fromJson(List<dynamic> json) 

2。但是,这可能会破坏其他东西。 (为什么它会被定义为Map&lt;String, dynamic&gt;?)因此,要做的第二件事是将response.body从List&lt;dynamic&gt;操作到Map&lt;String,dynamic&gt;inside fetchEvento(),然后再将其发送到Evento.fromJson(),方法是类似于:

var map1 = Map.fromIterable(response.body, key: (e) => e.name, value: (e) => e.value); 

(您可以在此处阅读更多相关信息:https://bezkoder.com/dart-convert-list-map/)

我希望是选项 1!

【讨论】:

这有帮助吗?你能把参数改成 List 吗? 还没有......我几乎中风了,但我认为我更接近解决大声笑。我将更新我的问题和新错误。 终于搞定了!!这正是你所说的,我的 json 返回了一个对象列表,所以我需要在映射我的键之前处理这个问题,正如你在“选项 2”中建议的那样。我从你的回答中学到了很多,感谢您的指导! 当然!你永远不知道......它可能会帮助下一个人!

以上是关于错误:List<dynamic> 在获取 JSON 时不是 Map<String, dynamic> 类型的子类型的主要内容,如果未能解决你的问题,请参考以下文章

错误颤振:List<dynamic> 不是 Map<String, dynamic> 类型的子类型

错误:类型“Future<dynamic>”不是“List<dynamic>”类型的子类型。扑

出现“List<dynamic>”类型的错误不是“Map<String, dynamic>”类型的子类型

类型 'List<dynamic>' 不是类型 'Map<String, dynamic>' 的子类型在颤振应用程序中出现此错误

如何修复此错误类型“_InternalLinkedHashMap<String, dynamic>”不是“FutureOr<List<dynamic>>”类型的子类

Flutter GetX 和获取存储错误类型:'List<dynamic>' 不是匿名关闭后类型'Map<String, dynamic> 的子类型