如何在颤振中解析json?

Posted

技术标签:

【中文标题】如何在颤振中解析json?【英文标题】:How to parse json in flutter? 【发布时间】:2020-03-01 12:22:30 【问题描述】:

我想创建一个新闻应用,我使用 newsapi.org 作为来源。

我正在尝试获取来自 Http 库的 JSON 数据。

我在下面提供了完整的代码。

它没有给我任何错误,但没有加载数据,当我打印数据时,它打印一切正常,但我无法显示它。

我不知道是什么问题,但我所有的项目都停止了这个问题。

我正在为此代码寻找解决方案,因为它不起作用。

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:newly/services/networking.dart';
import 'package:newly/widgets/article.dart';

class NewsScreen extends StatefulWidget 
  @override
  _NewsScreenState createState() => _NewsScreenState();


class _NewsScreenState extends State<NewsScreen> 

  List<Article> articles = [];

  NetworkHelper networkHelper = NetworkHelper(
    url:
        'https://newsapi.org/v2/everything?q=bitcoin&apiKey=392495172bab4b3885ae93760df54b91',
  );

  Future<List<Widget>> getNews() async 
    var newsData = await networkHelper.getData();

    for (int i = 0; i < await newsData['articles'].length; i++) 
      var title = await newsData['articles'][i]['title'];
      var urlToImage = await newsData['articles'][i]['urlToImage'];
      var content = await newsData['articles'][i]['content'];
      var author = await newsData['articles'][i]['author'];
      var url = await newsData['articles'][i]['url'];

      print(title);
      print(urlToImage);
      print(url);
      print(content);
      print(author);
      print('123456789123456789123456789123456789');

      articles.add(
        Article(
          author: author,
          content: content,
          title: title,
          url: url,
          urlToImage: urlToImage,
        ),
      );

      print(articles[0].author);

    

    return articles;
  

  Future<List<Article>> showArticles() async 
    var data = await get(
      'https://newsapi.org/v2/everything?q=bitcoin&apiKey=392495172bab4b3885ae93760df54b91',
    );

    var dataDecoded = await json.decode(data.body);

    List<Article> articles = [];

    await dataDecoded.forEach(
      (article) 
        articles.add(
          Article(
            author: article['author'],
            content: article['content'],
            title: article['title'],
            url: article['url'],
            urlToImage: article['urlToImage'],
          ),
        );
      ,
    );

    return articles;
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.black,
        centerTitle: true,
        title: Text(
          'Newly',
          style: TextStyle(
            color: Colors.white,
          ),
        ),
      ),
      body: FutureBuilder(
        future: getNews(),
        builder: (context, snapshot) 
          return ListView(
            children: articles,
          );
        ,
      ),

    );
  

网络助手:

import 'package:http/http.dart' as http;
import 'dart:convert';

class NetworkHelper 
  NetworkHelper(this.url);

  final String url;

  Future getData() async 
    http.Response response = await http.get(url);

    if (response.statusCode == 200) 
      String data = response.body;

      return json.decode(data);
     else 
      print('something wrong');
      print(response.statusCode);
    
  

【问题讨论】:

能否请您出示您的NetworkHelper 班级? 我已经更新了 好的,我会回答的 【参考方案1】:

在处理 json 数据时

最好的做法是为此创建一个模型,然后通过 api 获取数据

创建一个模型和一个类很容易,不费力,让你的工作很容易;)

用于为您的项目创建模型

访问https://javiercbk.github.io/json_to_dart/

只需copy your json datapaste in the textField,您只需单击一下即可准备好模型类

用于访问数据

Test _test = Test.fromJson(response.body);

就是这样。

参考下图

【讨论】:

转换响应模型的简单方法。 但仍然没有从响应中获取数据相同的错误 - 方法 '[]' 在 null 上调用。 E/颤振(8569):接收者:空 @s.j 该错误反映了从 api 端您没有获得任何数据,或者您可能没有正确访问它。尝试先检查响应【参考方案2】:

您也可以使用 FutureBuilder 来完成此操作,如果您愿意,@Mustafa 答案将起作用。

Future<List<Article>> showArticles() async 
var data = await networkHelper.getData();

List<Article> articlesArr = [];

await data['articles'].forEach(
  (article) 
    articlesArr.add(
      Article(
        author: article['author'],
        content: article['content'],
        title: article['title'],
        url: article['url'],
        urlToImage: article['urlToImage'],
      ),
    );
  ,
);
return articlesArr;


@override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.black,
        centerTitle: true,
        title: Text(
          'Newly',
          style: TextStyle(
            color: Colors.white,
          ),
        ),
      ),
      body: FutureBuilder<List<Article>>(
        future: showArticles(),
        builder: (context, snapshot) 
          if (snapshot.hasData) 
            return ListView(
              children: snapshot.data.map((article) 
                return Container(
                  padding: EdgeInsets.all(8.0),
                  child: Text(article.author),
                );
              ).toList(),
            );
           else 
            return Container(
              color: Colors.blue,
            );
          
        ,
      ),
    );
  

【讨论】:

【参考方案3】:

问题在于显示文章。而且正如@ISpam Ossama 所说,你必须使用 setState 将数据添加到这样的列表中。

void getNews() async 
var newsData = await networkHelper.getData();

for (int i = 0; i < newsData['articles'].length; i++) 
  var title = newsData['articles'][i]['title'];
  var urlToImage = newsData['articles'][i]['urlToImage'];
  var content = newsData['articles'][i]['content'];
  var author = newsData['articles'][i]['author'];
  var url = newsData['articles'][i]['url'];

  print(title);
  print(urlToImage);
  print(url);
  print(content);
  print(author);
  print('123456789123456789123456789123456789');
  setState(() 
   articles.add(
    Article(
      author: author,
      content: content,
      title: title,
      url: url,
      urlToImage: urlToImage,
    ),
  );
  );
  print(articles[0].author);


现在,你必须像这样显示文章。

ListView.builder(
          itemCount: articles.length,
          itemBuilder: (BuildContext ctxt, int index) 
            return Text(articles[index].title);
          ,
        )

希望对你有帮助!

【讨论】:

为什么在所有语句中都使用 await ?喜欢,await newsData['articles'][i]['title']; 并且还在setstate中发出。因为如果我们得到 1000 个数据,那么 Widget 将重建 1000 次。它应该在 for 循环之外。 是的你是对的,我真的很抱歉,我没有注意到,我会更新答案 我了解 await 问题,但是 setState 的替代解决方案是什么? 先在本地数组中添加所有数据,然后在for循环之后用全局设置状态。【参考方案4】:

在将文章添加到数组之前尝试 setState

【讨论】:

以上是关于如何在颤振中解析json?的主要内容,如果未能解决你的问题,请参考以下文章

如何在颤振中解析json

如何在颤振中解析这个复杂的json

如何在颤振中解析json?

如何使用我的图像在本地的颤振解析 json 文件中的图像?

颤振 - 在 null 上调用了方法“[]”(解析 json)

在颤振中解析json对象