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

Posted

技术标签:

【中文标题】如何在 Flutter 中从 API 获取 JSON 数据【英文标题】:How to get JSON data from an API in flutter 【发布时间】:2019-10-16 20:51:29 【问题描述】:

自从我昨天开始对我的项目进行编码以来,我面临着同样的问题,该项目的一部分是从给定的 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();
            ,
          ),
        ),
      ),
    );
  

我只得到以下消息:类型列表动态不是映射字符串类型的子类型,动态

任何帮助将不胜感激。 提前致谢。

【问题讨论】:

【参考方案1】:

试试下面的代码:

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

【讨论】:

【参考方案2】:

您的 JSON 响应的类型为 List&lt;dynamic&gt;,但您正在接受 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();

  

豆类

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()
    );
  

【讨论】:

我收到 14 个错误,这对我不起作用,名称 Post 不是类型,它不能用作类型参数。这是错误之一。 在 main 函数中添加 PostHome 到 runApp,现在运行良好。 我怎样才能在屏幕上打印它们而不仅仅是在控制台中? 你必须在你的视图中使用 listview。 怎么用?【参考方案3】:

你需要改变你的班级。您需要根据 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 类。这样可以节省很多时间。

【讨论】:

【参考方案4】:
**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,
                                            ),
                                          ),
                                        ),
    )

【讨论】:

以上是关于如何在 Flutter 中从 API 获取 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter 中从 API 获取数据

Flutter中从api获取数据时出错

如何在flutter中从record_mp3包中为api上传mp3文件

Flutter中从API获取数据时出现格式异常

http包在flutter中从api获取错误的图像url

如何在flutter中从API创建多个复选框