Flutter 中的 API 调用在第一次加载应用程序时不会加载所需的 JSON - Flutter

Posted

技术标签:

【中文标题】Flutter 中的 API 调用在第一次加载应用程序时不会加载所需的 JSON - Flutter【英文标题】:A call to API in Flutter doesn't load the required JSON the first time app is loaded - Flutter 【发布时间】:2018-10-02 01:31:03 【问题描述】:

我最近在学习用 Flutter 编写代码,并正在 ios 上使用它构建一个应用程序。因此,我想构建一个包含 NASA APOD API 的设备。

我创建了一个简单的 UI 并设置了一个带有图像视图的卡片,它将在从 API 的 JSON 传递 url 后加载图像。

JSON:


"copyright": "Panther Observatory", 
"date": "2006-04-15", 
"explanation": "In this stunning cosmic vista, galaxy M81 is on the left surrounded by blue spiral arms.  On the right marked by massive gas and dust clouds, is M82.  These two mammoth galaxies have been locked in gravitational combat for the past billion years.   The gravity from each galaxy dramatically affects the other during each hundred million-year pass.  Last go-round, M82's gravity likely raised density waves rippling around M81, resulting in the richness of M81's spiral arms.  But M81 left M82 with violent star forming regions and colliding gas clouds so energetic the galaxy glows in X-rays.  In a few billion years only one galaxy will remain.", 
"hdurl": "https://apod.nasa.gov/apod/image/0604/M81_M82_schedler_c80.jpg", 
"media_type": "image", 
"service_version": "v1", 
"title": "Galaxy Wars: M81 versus M82", 
"url": "https://apod.nasa.gov/apod/image/0604/M81_M82_schedler_c25.jpg" ,

现在我从这个 JSON 中获取 URL 并将其转换为字符串并将其传递给 Image.Network 函数。

当我第一次运行应用程序时。图片无法加载并给我一个错误

但是在我点击 Visual Studio Code 调试器控制台上的 Refresh 按钮之后

代码将运行并给我所需的输出。

所以问题是第一次加载应用程序时,它总是抛出一个错误,说明 url 未定义,但在刷新应用程序后,图像和所有数据都从 API 调用加载。 在这种情况下可能是什么错误。我认为这与 Flutter 上的状态有关。任何帮助表示赞赏。!!

这里是代码

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

class Home extends StatefulWidget 
  @override
  StateApodCall createState() => new StateApodCall();


class StateApodCall extends State<Home> 
  final url = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY";
  List resBody;
  String imageUrl;
  String imageTitle;

  Future<String> getAPODData() async
    var res = await http
    .get(Uri.encodeFull(url), headers: "Accept": "application/json");

    var resBody = json.decode(res.body);
    print(resBody);
    print(resBody["copyright"]);
    imageUrl = resBody["hdurl"];
    imageTitle = resBody["title"];
    print(imageUrl);
    return "Success!!";
  

  @override
  initState() 
    super.initState();
    this.getAPODData();
  

  @override
  Widget build(BuildContext context) 
    return new Container(
      decoration: new BoxDecoration(
        gradient: new LinearGradient(
          colors: [
            const Color(0xFF1ca2e3),
            const Color(0xFF1450a3)
          ],
          begin: const FractionalOffset(1.0, 0.5),
          end: const FractionalOffset(0.3, 0.1),
          stops: [0.0, 0.5],
          tileMode: TileMode.clamp
        ),
      ),
      child: new Scaffold(
        backgroundColor: Colors.transparent,
        appBar: new AppBar(
          backgroundColor: const Color(0xFF124489),
          elevation: 20.0,
          leading: new IconButton(
            icon: new Icon(Icons.menu),
            onPressed: () 

            
          ),
          title: new Text(
            "APOD",
            style: const TextStyle(
              color: Colors.white,
              fontFamily: 'Poppins',
              fontWeight: FontWeight.w600,
              fontSize: 34.0
              ),
            ),
        ),
        body: new ListView(
          children : [
            new Card(
              elevation: 3.0,
              child: new Column(
                children: [
                  new Image.network(
                    imageUrl,
                    width: double.infinity,
                    fit: BoxFit.fitWidth,
                  ),
                ],
              ),
            ),
            new Card(
              elevation: 2.0,
              child: new Text(imageTitle),
            ),
          ],
        ),
      )
    );
  

【问题讨论】:

【参考方案1】:

有多种方法可以解决此问题。您可以简单地添加一个ProgressIndicator,当 API 调用完成时,它将被 ListView 替换。

imageUrl!=null? new ListView(
//build
) : new Center(child:new CircularProgressIndicator()),

设置网址时不要忘记添加setState()调用

setState(()
imageUrl = resBody["hdurl"];
);

【讨论】:

哇非常感谢!这很有效,感谢您的快速回复! :) 你知道如何让它成为一个确定的进度条吗!因为他们说将值设置为非空,但我不能【参考方案2】:

为了解决这个问题,我在嵌套语句的主体中添加了这段代码!

body: imageUrl != null ? new ListView(
      children: [
          new Card(
            elevation: 3.0,
            child: new Column(
              children: [
                new Image.network(
                  imageUrl,
                  width: double.infinity,
                  fit: BoxFit.fitWidth,
                ),
              ],
            ),
          ),
          new Card(
            elevation: 2.0,
            child: new Text(imageTitle),
          )
        ],
    ) : new Center(child:new CircularProgressIndicator(
      strokeWidth: 3.0,
    )),

还包括setState函数

this.setState(()
  resBody = json.decode(res.body);
  imageUrl = resBody["hdurl"];
  imageTitle = resBody["title"];
);

【讨论】:

【参考方案3】:

android API 28 和 iOS 9 开始,这些平台默认禁用不安全的 HTTP 连接。

通过此更改,Flutter 还禁用了移动平台上的不安全连接。其他平台(桌面、网络等)不受影响。

您可以通过遵循特定于平台的指南来定义特定于域的网络策略来覆盖此行为。有关详细信息,请参阅下面的迁移指南。

与平台非常相似,应用程序仍然可以打开不安全的套接字连接。 Flutter 不会在套接字级别强制执行任何策略;您将负责保护连接。

请阅读本指南https://flutter.dev/docs/release/breaking-changes/network-policy-ios-android

【讨论】:

以上是关于Flutter 中的 API 调用在第一次加载应用程序时不会加载所需的 JSON - Flutter的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:如何在加载页面之前从 Api 获取数据 [关闭]

Flutter如何用调用RestFul API

Flutter:延迟加载来自 Firestore 的数据

如何测试从 Flutter 应用程序到 localhost 服务的 api 调用?

在 Spotify 应用程序 api 中链接加载调用

如何在flutter的build方法中调用provider中的方法?