运行我的应用程序时,它会引发很多错误,并且设备上的红色/黄色错误屏幕会自动刷新并向我显示预期的输出。
从日志中,我可以看到我的对象首先以null返回,然后以某种方式更新并得到输出。
我最近启动了Android Dev(Flutter)
我尝试遵循一些在线指南,还阅读了有关异步响应的相关问题,但是没有故障排除对我有帮助。 我最大的问题是我无法弄清楚到底是什么问题。
在我的_AppState类中:
void initState() {
super.initState();
fetchData();
}
fetchData() async {
var cityUrl = "http://ip-api.com/json/";
var cityRes = await http.get(cityUrl);
var cityDecodedJson = jsonDecode(cityRes.body);
weatherCity = WeatherCity.fromJson(cityDecodedJson);
print(weatherCity.city);
var weatherUrl = "https://api.openweathermap.org/data/2.5/weather?q=" +
weatherCity.city +
"," +
weatherCity.countryCode +
"&appid=" +
//Calling open weather map's API key from apikey.dart
weatherKey;
var res = await http.get(weatherUrl);
var decodedJson = jsonDecode(res.body);
weatherData = WeatherData.fromJson(decodedJson);
print(weatherData.weather[0].main);
setState(() {});
}
预期输出(终端):
Mumbai
Rain
实际输出(终端):https://gist.github.com/Purukitto/99ffe63666471e2bf1705cb357c2ea32(实际错误已超过StackOverflow的主体限制)
答案 0 :(得分:1)
async
和await
是一种在Dart中处理异步编程的机制。
异步操作让您的程序在等待时完成工作 完成另一项操作。
因此,只要某个方法被标记为async
,您的程序就不会为该方法的完成而暂停,只是假设它会在将来的某个时刻完成。
示例:错误地使用了异步函数
以下示例显示了使用异步函数getUserOrder()
的错误方法。
String createOrderMessage () {
var order = getUserOrder();
return 'Your order is: $order';
}
Future<String> getUserOrder() {
// Imagine that this function is more complex and slow
return Future.delayed(Duration(seconds: 4), () => 'Large Latte');
}
main () {
print(createOrderMessage());
}
如果运行上述程序,它将产生以下输出-
Your order is: Instance of '_Future<String>'
这是因为,由于该方法的返回类型被标记为Future,因此程序会将其视为异步方法。
要获取用户的订单,createOrderMessage()
应致电getUserOrder()
并等待其完成。因为createOrderMessage()
不等待getUserOrder()
完成,所以createOrderMessage()
无法获得getUserOrder()
最终提供的字符串值。
异步并等待
async和await关键字提供了一种声明性的方式来定义异步函数并使用其结果。
因此,每当您声明一个函数为async
时,都可以在任何方法调用之前使用关键字await
,这将迫使该程序在该方法完成之前无法继续进行操作。
关键点
在您的情况下,fetchData()
函数被标记为async
,并且您正在使用await
等待网络调用完成。
但是这里fetchData()
的返回类型为Future<void>
,因此,当您在initState()
内调用方法时,由于{{1} }不能标记为async/ await
。
因此,该程序不等待整个initState()
方法的完成,而是尝试显示本质上为async
的数据。
而且,由于在数据加载到fetchData()
中之后调用了null
,所以屏幕刷新了,一段时间后您可以看到详细信息。
出现红色和黄色屏幕错误。
解决方案
解决此问题的方法是,您可以在屏幕上显示加载指示器,直到数据完全加载为止。
您可以使用setState()
变量并根据该变量的值更改UI。
示例-
fetchData()
希望这会有所帮助!
答案 1 :(得分:0)
您必须等到api的数据到达。快速解决方案是将一个空合并运算符放在保存未来数据的变量上,如下所示:
String text;
fetchData() async {
//...
text = weatherData.weather[0].main ?? 'Waiting api response...';
//...
}
// in your build method
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Text(text), //this will render "Waiting api response" first, and when the api result arrive, it will change
),
);
}
否则,您可以使用futureBuilder
小部件来实现。但是您必须将每个api放置到不同的函数中,并将其更改为Future,以便它具有返回值。
Future fetchDataCity() async {
// your code
weatherCity = WeatherCity.fromJson(cityDecodedJson);
return weatherCity;
}
Future fetchDataWeather() async {
// your code
weatherData = WeatherData.fromJson(decodedJson);
return weatherData;
}
// in your build method
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: FutureBuilder(
future: fetchDataWeather(), // a previously-obtained Future or null
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState)
case ConnectionState.active:
case ConnectionState.waiting:
return Text('Awaiting result...'); //or a placeholder
case ConnectionState.done:
if (snapshot.hasError){
return Text('Error: ${snapshot.error}');
} else {
return Text('Error: ${snapshot.data}');
}
},
) //FutureBuilder
),
);
}