android - 获取异步函数的 NULL 值(在使用 await 之后)然后更新为新值

标签 android flutter dart async-await future

当我运行我的应用程序时,它会引发很多错误,并且我的设备上的红色/黄色错误屏幕会自动刷新并显示预期的输出。

从日志中我可以看到,首先我的对象返回为 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 的正文限制)

截图:
At run initial
After a few seconds

最佳答案

asyncawait是一种在 Dart 中处理异步编程的机制。

Asynchronous operations let your program complete work while waiting for another operation to finish.



所以每当一个方法被标记为 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 ,程序会将is视为异步方法。

获取用户订单,createOrderMessage()应调用 getUserOrder()并等待它完成。因为createOrderMessage()不等待getUserOrder()完成,createOrderMessage()获取不到 getUserOrder() 的字符串值最终提供。

异步和等待

async 和 await 关键字提供了一种声明方式来定义异步函数并使用它们的结果。

因此,每当您将函数声明为 async ,您可以使用关键字await在任何方法调用之前,这将强制程序在方法完成之前不继续进行。

例子

在您的情况下,fetchData()函数标记为async而您正在使用 await等待网络调用完成。

但是这里 fetchData()返回类型为 Future<void>因此,当您调用 initState() 中的方法时你必须这样做而不使用 async/ await自从 initState()无法标记 async .

所以程序不会等待 fetchData() 的完成。方法作为一个整体,并尝试显示本质上是 null 的数据.
既然你调用 setState()fetchData() 内部加载数据后,屏幕刷新,一段时间后您可以看到详细信息。

因此出现红色和黄色屏幕错误。

解决方案

此问题的解决方案是您可以在屏幕上显示加载指示器,直到数据完全加载。

您可以使用 bool变量并根据该变量的值更改 UI。

示例 -
class _MyHomePageState extends State<MyHomePage> {
  bool isLoading = false;

  void initState() {
    super.initState();
    fetchData();
 }

 fetchData() async {
   setState(() {
     isLoading = true; //Data is loading
   });
   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(() {
      isLoading = false; //Data has loaded
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: isLoading ? Center(child : CircularProgressIndicator())
      : Container(), //Replace this line with your actual UI code
    );
  }
}

希望这可以帮助!

关于android - 获取异步函数的 NULL 值(在使用 await 之后)然后更新为新值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57551482/

相关文章:

asynchronous - Stream.last 回调从不触发

android - 在底部导航 flutter 后面扩展容器

flutter - Flutter中如何在NetworkImage()中添加网络图片列表

android - Fragment 中的 MapView(Android 4.0 或更高版本)

java - 如何绘制Flappy Bird地面?

java - 如何将点击处理程序链接到 fragment 以进行数据绑定(bind)?

flutter - 失败: Build failed with an exception (Shared preference and gradle wrapper properties)

dart - 如何检查当前路线是哪条?

android模拟器永远启动

firebase - 只有 Android 应用程序模块可以连接到 Firebase 在线项目