json - 错误:列表不是 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": [
]
}
]
}
]
我做错了什么??
解决方案
问题是您收到的数据与预期的数据接收方式不匹配。具体来说,您正在尝试将带有 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!
推荐阅读
- r - 如何防止“隐藏”操作按钮重置 R 闪亮中的所有用户输入?
- migration - 如何将 JIRA 云备份 zip 文件从我们的旧 JIRA 云导入到新的 JIRA 云帐户?
- typescript - Ionic5 Capacitor AppRate 未安装
- mongodb - 没有 ODBC 的 mongosqld + PowerBI
- android - 为什么导入swing会在kotlin中给我一个错误
- javascript - 如何在使用默认分页时使用复选框选择多行 gridivew。我只从 gridivew 的第一页获取数据
- javascript - 浏览器不会在 React App 中渲染图像
- c# - 在控制台窗口和 XML 文件上生成 XML 类型输出的 LINQ 查询
- html - 如何选择特定版本的 FontAwesome 图标?
- python - AttributeError:部分初始化的模块“pyproj”没有属性“network”(很可能是由于循环导入)