我最近正在学习在 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 调试器控制台上的“刷新”按钮后
所以问题是第一次加载应用程序时,它总是抛出一个错误,指出 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),
),
],
),
)
);
}
}
有多种方法可以解决这个问题。您只需添加一个
ProgressIndicator
,API 调用完成后将被 ListView
替换。
imageUrl!=null? new ListView(
//build
) : new Center(child:new CircularProgressIndicator()),
设置url时不要忘记添加
setState()
调用
setState((){
imageUrl = resBody["hdurl"];
});
为了解决这个问题,我在嵌套语句的主体中添加了这段代码!
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"];
});
从 Android API 28 和 iOS 9 开始,这些平台默认禁用不安全的 HTTP 连接。
通过此更改,Flutter 还禁用移动平台上的不安全连接。其他平台(桌面、网络等)不受影响。
您可以通过遵循特定于平台的指南来定义特定于域的网络策略来覆盖此行为。有关详细信息,请参阅下面的迁移指南。
与平台非常相似,应用程序仍然可以打开不安全的套接字连接。 Flutter 不会在套接字级别强制执行任何策略;您将负责确保连接的安全。
请阅读本指南https://flutter.dev/docs/release/writing-changes/network-policy-ios-android