我正试图扑朔迷离地进行API调用。当解析一个简单的JSON时,它工作正常,但是当我尝试解析一个List时,它显示错误,我该怎么办?
我的JSON
{
"posts": [
{
"id": 1,
"title": "Post 1"
},
{
"id": 2,
"title": "Post 2"
},
{
"id": 3,
"title": "Post 3"
}
],
"comments": [
{
"id": 1,
"body": "some comment",
"postId": 1
},
{
"id": 2,
"body": "some comment",
"postId": 1
}
],
"profile": {
"name": "typicode"
}
}
我的PODO类别
class Welcome {
List<Post> posts;
List<Comment> comments;
Profile profile;
Welcome({
this.posts,
this.comments,
this.profile,
});
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
posts: List<Post>.from(json["posts"].map((x) => Post.fromJson(x))),
comments: List<Comment>.from(json["comments"].map((x) => Comment.fromJson(x))),
profile: Profile.fromJson(json["profile"]),
);
Map<String, dynamic> toJson() => {
"posts": List<dynamic>.from(posts.map((x) => x.toJson())),
"comments": List<dynamic>.from(comments.map((x) => x.toJson())),
"profile": profile.toJson(),
};
}
class Comment {
int id;
String body;
int postId;
Comment({
this.id,
this.body,
this.postId,
});
factory Comment.fromJson(Map<String, dynamic> json) => Comment(
id: json["id"],
body: json["body"],
postId: json["postId"],
);
Map<String, dynamic> toJson() => {
"id": id,
"body": body,
"postId": postId,
};
}
class Post {
int id;
String title;
Post({
this.id,
this.title,
});
factory Post.fromJson(Map<String, dynamic> json) => Post(
id: json["id"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
};
}
class Profile {
String name;
Profile({
this.name,
});
factory Profile.fromJson(Map<String, dynamic> json) => Profile(
name: json["name"],
);
Map<String, dynamic> toJson() => {
"name": name,
};
}
我的api_call.dart文件
import 'dart:convert';
import 'package:api/api/modal.dart';
import 'package:http/http.dart';
class HttpService{
final String url = "https://my-json-server.typicode.com/typicode/demo/db";
Future<List<Welcome>> getPost() async {
Response response = await get(url);
if(response.statusCode == 200) {
List<dynamic> body = jsonDecode(response.body);
List<Welcome> wel = body.map((e) => Welcome.fromJson(e)).toList();
return wel;
}
}
}
我的widget.dart
import 'package:api/api/api_fetcher.dart';
import 'package:api/api/modal.dart';
import 'package:flutter/material.dart';
class News extends StatefulWidget {
@override
_NewsState createState() => _NewsState();
}
class _NewsState extends State<News> {
final HttpService http = HttpService();
@override
Widget build(BuildContext context) {
return SafeArea(
child: DefaultTabController(
length: 4,
child: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
title: Text(
'Trending Topics',
style: TextStyle(color: Colors.black, fontSize: 25),
),
automaticallyImplyLeading: false,
elevation: 0,
actions: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
'see all',
style: TextStyle(fontSize: 20, color: Colors.grey[600]),
),
),
),
],
bottom: TabBar(
labelColor: Colors.black,
unselectedLabelColor: Colors.black,
tabs: <Widget>[
Tab(
text: 'Tech',
),
Tab(
text: 'Art',
),
Tab(
text: 'Sports',
),
Tab(
text: 'Nation',
),
],
),
),
body: TabBarView(
children: <Widget>[
Container(
child: FutureBuilder(
future: http.getPost(),
builder: (context, snapshot) {
if(snapshot.hasData){
List<Welcome> welc = snapshot.data;
return ListView(
children: welc.map((Welcome welcome) => ListTile(
title: Text(welcome.posts.length.toString()),
)),
);
}
},
),
),
Container(),
Container(),
Container(),
],
),
),
),
);
}
}
它显示了我尝试通过ListTile访问帖子时出现的错误。
请给我一个解决方案。
提前感谢。
此json具有一个Welcome类,因此您应该将getPost()返回的函数仅Welcome,因此,您应该更改显示欢迎状态的窗口小部件,并带有帖子列表和/或评论列表。尝试这样:
class Welcome {
List<Post> posts;
List<Comment> comments;
Profile profile;
Welcome({
this.posts,
this.comments,
this.profile,
});
factory Welcome.fromJson(Map<String, dynamic> json) {
return Welcome(
posts: json['posts'] != null
? json['posts'].map<Post>((json) => Post.fromJson(json)).toList()
: null,
comments: json['comments'] != null
? json['comments']
.map<Comment>((json) => Comment.fromJson(json))
.toList()
: null,
profile:
json['profile'] != null ? Profile.fromJson(json['profile']) : null,
);
}
}
class HttpService {
static String url = "https://my-json-server.typicode.com/typicode/demo/db";
static Future<Welcome> getPost() async {
Response response = await get(url);
if (response.statusCode == 200) {
final parsed = json.decode(response.body).cast<String, dynamic>();
return Welcome.fromJson(parsed);
}
}
}
在您的代码中,您使用map
映射了一些对象,然后将它们分配给小部件的children
,在映射后也使用了.toList()
。
我无法从您的代码中得到的东西是,您有一个Wellcome
模型,其中包含一列帖子和评论以及一个个人资料,您的示例JSON等于一个Welcome
,但是在您获取的代码中您尝试在窗口小部件中将其映射为Wellcome
列表的数据。
另一件事是在将来的构建器中,最好定义它将要获得的类型:
...
FutureBuilder<Welcome>(
future: http.getPost(),
builder: (context, AsyncSnapshot<Welcome> snapshot) {
...
将来也需要花费一些时间才能完成,因此在没有数据(尚未完成)的情况下,您应该返回另一个小部件,在这里我只是用到了:
return Center(child: CircularProgressIndicator());
我稍微更改了您的代码,结果是:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
home: News(),
));
}
class Welcome {
List<Post> posts;
List<Comment> comments;
Profile profile;
Welcome({
this.posts,
this.comments,
this.profile,
});
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
posts: List<Post>.from(json["posts"].map((x) => Post.fromJson(x))),
comments: List<Comment>.from(
json["comments"].map((x) => Comment.fromJson(x))),
profile: Profile.fromJson(json["profile"]),
);
Map<String, dynamic> toJson() => {
"posts": List<dynamic>.from(posts.map((x) => x.toJson())),
"comments": List<dynamic>.from(comments.map((x) => x.toJson())),
"profile": profile.toJson(),
};
}
class Comment {
int id;
String body;
int postId;
Comment({
this.id,
this.body,
this.postId,
});
factory Comment.fromJson(Map<String, dynamic> json) => Comment(
id: json["id"],
body: json["body"],
postId: json["postId"],
);
Map<String, dynamic> toJson() => {
"id": id,
"body": body,
"postId": postId,
};
}
class Post {
int id;
String title;
Post({
this.id,
this.title,
});
factory Post.fromJson(Map<String, dynamic> json) => Post(
id: json["id"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
};
}
class Profile {
String name;
Profile({
this.name,
});
factory Profile.fromJson(Map<String, dynamic> json) => Profile(
name: json["name"],
);
Map<String, dynamic> toJson() => {
"name": name,
};
}
class HttpService {
final String url = "https://my-json-server.typicode.com/typicode/demo/db";
Future<Welcome> getPost() async {
var response = await http.get(url);
if (response.statusCode == 200) {
var body = json.decode(response.body);
return Welcome.fromJson(body);
}
}
}
class News extends StatefulWidget {
@override
_NewsState createState() => _NewsState();
}
class _NewsState extends State<News> {
final HttpService http = HttpService();
@override
Widget build(BuildContext context) {
return SafeArea(
child: DefaultTabController(
length: 4,
child: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
title: Text(
'Trending Topics',
style: TextStyle(color: Colors.black, fontSize: 25),
),
automaticallyImplyLeading: false,
elevation: 0,
actions: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Center(
child: Text(
'see all',
style: TextStyle(fontSize: 20, color: Colors.grey[600]),
),
),
),
],
bottom: TabBar(
labelColor: Colors.black,
unselectedLabelColor: Colors.black,
tabs: <Widget>[
Tab(
text: 'Tech',
),
Tab(
text: 'Art',
),
Tab(
text: 'Sports',
),
Tab(
text: 'Nation',
),
],
),
),
body: TabBarView(
children: <Widget>[
Container(
child: FutureBuilder<Welcome>(
future: http.getPost(),
builder: (context, AsyncSnapshot<Welcome> snapshot) {
if (snapshot.hasData) {
Welcome welc = snapshot.data;
return ListView(
children: welc.posts
.map((post) => ListTile(
title: Text(post.title),
))
.toList());
}
return Center(child: CircularProgressIndicator());
},
),
),
Container(),
Container(),
Container(),
],
),
),
),
);
}
}