如何从Flutter中的API获取JSON数据

时间:2019-05-31 08:05:53

标签: json api http flutter

自从我昨天开始在我的项目上编码以来,我面临着同样的问题,该项目的一部分是从给定的api获取一些json数据。

我的api链接是:http://alkadhum-col.edu.iq/wp-json/wp/v2/posts?_embed

我正在使用Flutter SDK,但我很困惑为什么它不能与我合作!我的工作是仅获取链接,标题和source_url对象,但我无法获取它。

我在flutter文档中尝试了以下代码
https://flutter.dev/docs/cookbook/networking/fetch-data 并根据我的需要进行了一些修改后没有任何数据。

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

Future<Post> fetchPost() async {
  final response =
      await http.get('http://alkadhum-col.edu.iq/wp-json/wp/v2/posts/');

  if (response.statusCode == 200) {
    // If the call to the server was successful, parse the JSON
    return Post.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}

class Post {

  final int id;
  String title;
  String link;


  Post({this.id, this.title, this.link});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      id: json['id'],
      title: json['title'].toString(),
      link: json['link'].toString()
    );
  }
}

void main() => runApp(MyApp(post: fetchPost()));

class MyApp extends StatelessWidget {
  final Future<Post> post;

  MyApp({Key key, this.post}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Fetch Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Fetch Data Example'),
        ),
        body: Center(
          child: FutureBuilder<Post>(
            future: post,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text(snapshot.data.link);
              } else if (snapshot.hasError) {
                return Text("${snapshot.error}");
              }

              // By default, show a loading spinner
              return CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}

我只有下面的消息:
动态类型列表不是动态映射字符串类型的子类型

任何帮助将不胜感激。
预先感谢。

4 个答案:

答案 0 :(得分:1)

您的JSON响应的类型为List<dynamic>,但是您正在Map String, dynamic中进行响应,但是您可以执行以下操作

     import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:clickmeetplay/iam/user/postbean.dart';
import 'package:http/http.dart' as http;

class PostHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: Scaffold(body: PostScreen(),),);
  }
}

class PostScreen extends StatefulWidget {
  @override
  _PostScreenState createState() => _PostScreenState();
}

class _PostScreenState extends State<PostScreen> {

  List<Post> _postList =new List<Post>();

  Future<List<Post> > fetchPost() async {
    final response =
    await http.get('http://alkadhum-col.edu.iq/wp-json/wp/v2/posts/');

    if (response.statusCode == 200) {
      // If the call to the server was successful, parse the JSON
      List<dynamic> values=new List<dynamic>();
      values = json.decode(response.body);
      if(values.length>0){
        for(int i=0;i<values.length;i++){
          if(values[i]!=null){
            Map<String,dynamic> map=values[i];
            _postList .add(Post.fromJson(map));
            debugPrint('Id-------${map['id']}');
          }
        }
      }
      return _postList;

    } else {
      // If that call was not successful, throw an error.
      throw Exception('Failed to load post');
    }
  }
  @override
  Widget build(BuildContext context) {
    return Container();
  }

  @override
  void initState() {

    fetchPost();

  }
}

Bean类

class Post {

  final int id;
  String title;
  String link;


  Post({this.id, this.title, this.link});

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
        id: json['id'],
        title: json['title'].toString(),
        link: json['link'].toString()
    );
  }
}

enter image description here

答案 1 :(得分:0)

尝试以下代码:

factory Post.fromMap(Map<String, dynamic> json) {
  return Post(
    id: json['id'],
    title: json['title'].cast<String>(),
    link: json['link'].cast<String>()
  );
}

答案 2 :(得分:0)

您需要更改课程。您需要根据JSON响应创建类结构。

class Post {
  int id;
  String title;
  String link;

  Post({this.id, this.title, this.link});

  factory Post.fromJson(Map<String, dynamic> json) {
     return Post(
         id: json['id'],
         title: title = json['title'] != null ? new Title.fromJson(json['title']) : null;
         link: json['link'].toString()
        );
    }
 }


class Title {
    String rendered;

    Title({this.rendered});

     Title.fromJson(Map<String, dynamic> json) {
          rendered = json['rendered'];
      }

       Map<String, dynamic> toJson() {
          final Map<String, dynamic> data = new Map<String, dynamic>();
          data['rendered'] = this.rendered;
          return data;
        }
  }

然后,在您的API方法中。作为响应,您得到的是一个JSON数组。因此,将其放在列表中,并将响应转换为JSON类。

Future<List<Post>> fetchPost() async {
  final response =
        await http.get('http://alkadhum-col.edu.iq/wp-json/wp/v2/posts/');

     if (response.statusCode == 200) {
       // If the call to the server was successful, parse the JSON
        var lst = response.body as List;
        return lst.map((d) => Post.fromJson(d)).toList();
      } else {
        // If that call was not successful, throw an error.
          throw Exception('Failed to load post');
      }
 }

您始终可以使用https://javiercbk.github.io/json_to_dart/之类的工具从复杂的JSON创建Dart类。这样可以节省很多时间。

答案 3 :(得分:-1)

**Create Api Class**

    class ApiUtils {
      static String baseUrl = "http://example/";
    }

**Create Model**

    class EventModel {
      String title;
    
      EventModel({this.title});
    
      EventModel.fromJson(Map<String, dynamic> json) {
        title = json['Title'] ?? "";
      
      }
    }

**Create Service**

    import 'package:http/http.dart' as http;
    import 'package:NoticeModel.dart';
    import 'dart:convert';
    
    class NoticeService {
      bool error = false;
      bool loading = true;
      var notice;
      bool noticeDetailserror = false;
      bool noticeetailsloading = true;
    
      Future<void> getNotice(dynamic input) async {
        try {
          noticeDetailserror = false;
    
          http.Response response = await http.post(ApiUtils.noticeApi,
              body: input, headers: {'Content-type': 'application/json'});
    
          Map data = jsonDecode(response.body);
          if (data["Status"] == true) {
            notice = data["Data"];
            notice = notice.map((_data) {
              return new NoticeModel.fromJson(_data);
            }).toList();
            print(notice);
            noticeetailsloading = false;
          } else {
            throw data;
          }
        } catch (e) {
          print(e);
          noticeetailsloading = false;
          noticeDetailserror = true;
        }
      }
    }

**Main Page**

 

    var body =
          json.encode({"IsActive": true, "IsDelete": false, "CompanyId": 18});
      List<dynamic> data;
      var count = 0;
      bool loading = true;
      bool error = false;
    
      void getNoticeDetails() async {
        setState(() {
          error = false;
          loading = true;
        });
    
        // SharedPreferences prefs = await SharedPreferences.getInstance();
    
        NoticeService instance = NoticeService();
        await instance.getNotice(body);
        data = instance.notice;
        if (instance.noticeDetailserror == false) {
          setState(() {
            count = data.length;
            loading = false;
          });
        } else {
          setState(() {
            loading = false;
            error = true;
          });
    
          Toast.show("Error Getting Data", context,
              duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM);
        }
      }
    
      @override
      void initState() {
        super.initState();
        getNoticeDetails();
      }
    
    body: loading == true
              ? LinearProgressIndicator()
              : error == true
                  ? RetryWidget(
                      onRetry: getNoticeDetails,
                    )
                  : SafeArea(
    SizedBox(
                                      width: 270,
                                          child: Text(
                                            data[index].title ?? "",
                                            maxLines: 1,
                                            overflow: TextOverflow.ellipsis,
                                            style: TextStyle(
                                              fontSize: 18,
                                              color: Colors.grey,
                                              fontWeight: FontWeight.bold,
                                            ),
                                          ),
                                        ),
    )