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

Pur*_*tto 5 android future async-await dart flutter

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

从日志中我可以看到,首先我的对象返回为空,稍后以某种方式更新并获得输出。

我最近开始了 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(() {});
  }
Run Code Online (Sandbox Code Playgroud)

预期输出(终端):

Mumbai
Rain
Run Code Online (Sandbox Code Playgroud)

实际输出(终端):https : //gist.github.com/Purukitto/99ffe63666471e2bf1705cb357c2ea32(实际错误是越过StackOverflow的body limit)

截图: 在运行初始 几秒钟后

Sid*_*kar 6

asyncawait是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());
}
Run Code Online (Sandbox Code Playgroud)

如果您运行上述程序,它将产生以下输出 -

Your order is: Instance of '_Future<String>'
Run Code Online (Sandbox Code Playgroud)

这是因为,由于方法的返回类型被标记为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
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!