Flutter API轮询函数问题:提前返回空URL致Dio下载报错
解决Flutter轮询API提前返回导致下载失败的问题
原代码的核心问题是Timer.periodic的回调是独立的异步执行流,_pollingForExport函数会在Timer启动后立刻返回初始的空字符串exportUrl,完全等不到轮询拿到有效URL的时机,这就导致后续dio.download调用时传入空URI,触发报错。
改用Completer可以手动控制Future的完成时机,让我们在轮询到有效URL或者出现错误时,再结束Future并返回结果。
修正后的轮询函数
Future<String> _pollingForExport(String url, Options options) async { final completer = Completer<String>(); Timer? timer; int retryCount = 0; const maxRetries = 10; // 设置最大轮询次数,避免无限循环 timer = Timer.periodic(const Duration(seconds: 3), (timer) async { retryCount++; try { final responseRequested = await dio.post( url, options: options, ); print('轮询响应: ${responseRequested.data}'); if (responseRequested.statusCode == 200 && responseRequested.data is String) { print('获取到导出URL: ${responseRequested.data}'); completer.complete(responseRequested.data as String); timer.cancel(); } else if (responseRequested.statusCode != 200) { completer.completeError(Exception('轮询API失败: 错误状态码 ${responseRequested.statusCode}')); timer.cancel(); } } catch (e) { completer.completeError(Exception('轮询请求异常: $e')); timer.cancel(); } // 达到最大重试次数仍未获取到URL,终止轮询并抛出错误 if (retryCount >= maxRetries) { completer.completeError(Exception('轮询超时: 未在指定次数内获取到导出URL')); timer.cancel(); } }); return completer.future; }
调用代码(增加错误捕获)
try { String exportUrl = await _pollingForExport(url, options); String downloadPath = (await getApplicationDocumentsDirectory()).path; final responseExport = await dio.download(exportUrl, '$downloadPath/export.txt', options: options); // 下载成功后的逻辑 } catch (e) { print('处理失败: $e'); // 提示用户错误信息 }
关键说明
Completer的作用是将异步操作的结果手动传递给调用者,只有当调用completer.complete()或completer.completeError()时,Future才会结束并返回结果/错误。- 添加
maxRetries最大重试次数,防止因API异常导致无限轮询。 - 路径拼接使用字符串插值,避免出现路径格式错误。
- 外层用
try-catch捕获所有异常,避免程序崩溃。
内容的提问来源于stack exchange,提问作者Tom Wiz
相关产品推荐
相关产品推荐

