在获取 JSON 时,json,flutter"/>

首页 > 解决方案 > 错误:列表不是 Map 类型的子类型在获取 JSON 时

问题描述

我正在使用 Flutter 构建一个事件应用程序,该应用程序从 Rails api 获取数据并显示其详细信息。我得到了与这个问题相同的错误,并且已经尝试了“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": [

        ]
      }
    ]
  }
]

我做错了什么??

标签: jsonflutter

解决方案


问题是您收到的数据与预期的数据接收方式不匹配。具体来说,您正在尝试将带有 is 类型的 response.body 传递List<dynamic>给正在查找的函数Map<String, dynamic>

我无法运行您的代码,但看起来问题发生在 FetchEvento 的这一行:

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

因为您将 response.body 与 type 传递List<dynamic>Evento.fromJson()期望类型的变量Map<String,dynamic>

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

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

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

factory Evento.fromJson(List<dynamic> json) {

2. 但是,这可能会破坏其他东西。(为什么还要将它定义为Map<String, dynamic>?)因此,要做的第二件事是在将 response.body 从 a发送List<dynamic>Map<String,dynamic>内部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!


推荐阅读