【问题标题】:How to parse json in flutter?如何在颤振中解析json?
【发布时间】: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 班级?
  • 我已经更新了
  • 好的,我会回答的

标签: arrays json parsing flutter dart


【解决方案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

    【讨论】:

      猜你喜欢
      • 2021-08-23
      • 2021-10-27
      • 2019-01-17
      • 2019-09-06
      • 2023-03-22
      • 2021-09-25
      • 2021-02-25
      • 2020-09-12
      • 2023-03-05
      相关资源
      最近更新 更多