如何编写轮询函数来轮询 API,直到返回 URL?

问题描述 投票:0回答:1

在 Flutter 中,我尝试编写一个函数,该函数定期调用 API,直到返回 URL,然后将该 URL 传递给另一个函数。 API 的工作原理是,在第一次调用时,它会响应已发出请求的确认。然后,一段时间后,它会生成一个URL,可以点击该URL来导出文件。

但是,我当前的错误是该函数在轮询完成之前结束,并且 URL 被分配给我想返回到另一个函数的

exportURL
变量。

我收到的错误是

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: DioException [unknown]: null
Error: Invalid argument(s): No host specified in URI 
,因为 URL 未正确传递到我的其他函数。

下面是我轮询 API 的函数。

Future<String> _pollingForExport(String url, Options options) async{
    String exportUrl = '';
    Timer.periodic(const Duration(seconds: 3), (timer) async {
      //Call API with post method again
      final responseRequested = await dio.post(
        url,
        options: options,
      );
      print('In polling mechanism, response requested is ${responseRequested.data}');

      //If successful request and the response is a url String, cancel the timer and exit Polling
      //We know if the response is a link if it just contains a string, which is the url
      if(responseRequested.statusCode == 200 && responseRequested.data is String){
        print('Link should be found. response is ${responseRequested.data}');
        exportUrl = responseRequested.data as String;
        timer.cancel();
      }
      //Else if there is a bad request, tell user error and return function
      else if (responseRequested.statusCode != 200){
        print('Error when polling API, bad request made');
        timer.cancel();
        return ;  //Not sure if I return here, but seems right
      }
    });

    return exportUrl;
  }

下面是轮询函数返回url的代码。它被传递到

dio.download
以导出文件。

String exportUrl = await _pollingForExport(url, options);
String downloadPath = (await getApplicationDocumentsDirectory()).path;
final responseExport = await dio.download(exportUrl, downloadPath + '.txt', options: options);

我尝试阅读有关 Flutter 计时器和异步函数的文档。我也尝试过不使用函数,只是将计时器固定在我需要的地方,但这也不起作用。

如有任何帮助,我们将不胜感激,谢谢!

flutter dart asynchronous polling
1个回答
0
投票

问题是你的函数立即返回,它不会“等待”计时器。

Future<String> _pollingForExport(String url, Options options) async{
    String exportUrl = '';
//This is not awaited
Timer.periodic(const Duration(seconds: 3), (timer) async {
      //Call API with post method again
      final responseRequested = await dio.post(
        url,
        options: options,
      );
      print('In polling mechanism, response requested is ${responseRequested.data}');

      //If successful request and the response is a url String, cancel the timer and exit Polling
      //We know if the response is a link if it just contains a string, which is the url
      if(responseRequested.statusCode == 200 && responseRequested.data is String){
        print('Link should be found. response is ${responseRequested.data}');
        exportUrl = responseRequested.data as String;
        timer.cancel();
      }
      //Else if there is a bad request, tell user error and return function
      else if (responseRequested.statusCode != 200){
        print('Error when polling API, bad request made');
        timer.cancel();
        return ;  //Not sure if I return here, but seems right
      }
    });

//this returns immediately
    return exportUrl;
  }

也许完成者会更好

Future<String> _pollingForExport(String url, Options options) async{
  final exportUrlCompleter = Completer<String>();


//This is not awaited
  Timer.periodic(const Duration(seconds: 3), (timer) async {
    //Call API with post method again
    final responseRequested = await dio.post(
      url,
      options: options,
    );
    print('In polling mechanism, response requested is ${responseRequested.data}');

    //If successful request and the response is a url String, cancel the timer and exit Polling
    //We know if the response is a link if it just contains a string, which is the url
    if(responseRequested.statusCode == 200 && responseRequested.data is String){
      print('Link should be found. response is ${responseRequested.data}');
      final exportUrl = responseRequested.data as String;
      timer.cancel();
      exportUrlCompleter.complete(exportUrl);
    }
    //Else if there is a bad request, tell user error and return function
    else if (responseRequested.statusCode != 200){
      print('Error when polling API, bad request made');
      exportUrlCompleter.completeError("Exception occurred");
      timer.cancel();
    }
  });

//this returns immediately
  return exportUrlCompleter.future;
}
© www.soinside.com 2019 - 2024. All rights reserved.