如何在Flutter中解析JSON中的列表

问题描述 投票:1回答:1

我正试图扑朔迷离地进行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访问帖子时出现的错误。

请给我一个解决方案。

提前感谢。

android api flutter flutter-layout
1个回答
0
投票

此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);
    }
  }
}

0
投票

在您的代码中,您使用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(),
            ],
          ),
        ),
      ),
    );
  }
}

© www.soinside.com 2019 - 2024. All rights reserved.