在 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 计时器和异步函数的文档。我也尝试过不使用函数,只是将计时器固定在我需要的地方,但这也不起作用。
如有任何帮助,我们将不胜感激,谢谢!
问题是你的函数立即返回,它不会“等待”计时器。
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;
}