简体   繁体   中英

Flutter load json in ListView return always empty data

I' m trying to build a simple app for viewing json data. I started with the example on flutter website: https://flutter.dev/docs/cookbook/networking/fetch-data

This is working.

Now I' m trying to load a List of comments from: https://jsonplaceholder.typicode.com/comments/

When I run the app I see only the circle loaded from CircularProgressIndicator. Why? I'm not able to get the data but I don' t understand why, can you help me? Here is the code:

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter json test',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter json test'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  Future<List<Comment>> _getComments() async {

    var data = await http.get("https://jsonplaceholder.typicode.com/comments/");
    List<Comment> comments = [];

    if(data.statusCode==200) {
      var jsonData = json.decode(data.body);

      for (var d in jsonData) {
        Comment comment = Comment(
            d["postId"],d["id"], d["name"], d["email"], d["body"]);

        comments.add(comment);
      }

      print(comments.length.toString());

      return comments;
    }
    else {
      throw Exception('Failed to load album');
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: Container(
        child: FutureBuilder(
          future: _getComments(),
          builder: (BuildContext context, AsyncSnapshot snapshot){
            if(snapshot.hasData){
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(
                    title: Text( snapshot.data[index]['name']),
                    subtitle: Text(snapshot.data[index]['email']),
                    onTap: (){
                      Navigator.push(context,
                          new MaterialPageRoute(builder: (context) => DetailPage(snapshot.data[index]))
                      );
                    },
                  );
                },
              );
            } else {
              return Center(
                child: CircularProgressIndicator(),
              );
            }
          },
        ),
      ),
    );
  }
}

class DetailPage extends StatelessWidget {

  final Comment comment;

  DetailPage(this.comment);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(comment.name),
        )
    );
  }
}


class Comment {
  final int postId;
  final String id;
  final String name;
  final String email;
  final String body;

  Comment(this.postId, this.id, this.name, this.email, this.body);

}

Can you give me any advice? Thank you!

You are returning Comment instances not Map instances so you should use the dot accessor. I'm sure if you check your console, you might see the error.

ListView.builder(
  itemCount: snapshot.data.length,
  itemBuilder: (BuildContext context, int index) {
    return ListTile(
      title: Text( snapshot.data[index].name), // Change here
      subtitle: Text(snapshot.data[index].email), // Change here
      onTap: () {
        Navigator.push(context,
         new MaterialPageRoute(builder: (context) => 
            DetailPage(snapshot.data[index]))
         );
      },
    );
  }
)

First, you need to convert your JSON data into Map<String, dynamic> and then parsed it into List . By looking at your code you have only converted data into List so the Type int is not a subtype of String error occurred . Also, you have not added an error statement into your FutureBuilder so you have to face difficulties to read error so please do check my answer

You need to call this CommentPage from your main.dart file

class CommentPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _homePage();
  }
}

class _homePage extends State<CommentPage> {
  Future<List<CommentModel>> getPostData() async {
    var url = "https://jsonplaceholder.typicode.com/comments";
    final responce = await http.get(url);
    final parsed = json.decode(responce.body).cast<Map<String, dynamic>>();
    return parsed.map<CommentModel>((json) {
      return CommentModel.fromJson(json);
    }).toList();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      body: Container(
        child: FutureBuilder<List<CommentModel>>(
          future: getPostData(),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (context, int index) {
                  return ListTile(
                      title: Text(snapshot.data[index].name),
                      subtitle: Text(snapshot.data[index].email));
                },
              );
            } else if (snapshot.hasError) {
              return Center(
                child: Text(snapshot.error.toString()),
              );
            }
            return Center(
              child: CircularProgressIndicator(),
            );
          },
        ),
      ),
    );
  }
}

And here is my model class. I created this by using this online tool.

class CommentModel {
  CommentModel({
    this.postId,
    this.id,
    this.name,
    this.email,
    this.body,
  });

  int postId;
  int id;
  String name;
  String email;
  String body;

  factory CommentModel.fromJson(Map<String, dynamic> json) => CommentModel(
    postId: json["postId"],
    id: json["id"],
    name: json["name"],
    email: json["email"],
    body: json["body"],
  );

  Map<String, dynamic> toJson() => {
    "postId": postId,
    "id": id,
    "name": name,
    "email": email,
    "body": body,
  };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM