如何等待 Dart 中异步下载的完成或错误?
How to await for the completion or error of an async download in Dart?
我想编写一个线性的多阶段流程(如下所示),从文件下载开始,并有进度:
/// Processes the database, from download to prices processing.
Future<void> updateDatabase() async {
//final fontText = await File('./example/cosmic.flf').readAsString();
//print(art.renderFiglet('updateDatabase'));
// == 1) download
print('1 ======== DOWNLOADING ==========');
try {
await startDownloading();
} catch (err) {}
// == 2) Decompress: Whatever download was ok or not, we decompress the last downloaded zip file we have locally
print('2 ======== DECOMPRESSING ========');
try {
await startDecompressing();
} catch (err) {}
// == i) Stage i, etc.
但是在我的下载阶段有些东西不起作用,因为它开始阶段 2) 前期阶段 1) 完成。
我的第一阶段(下载)是这样的:
/// Starts download procress
Future<void> startDownloading() async {
print("startDownloading…");
_state = DownloadState.downloading;
_progress = 0;
notifyListeners();
/// Database string url
final databaseUrlForInstantData = "https://XXX";
try {
final request = Request('GET', Uri.parse(databaseUrlForInstantData));
final StreamedResponse response = await Client().send(request);
final contentLength = response.contentLength;
// == Start from zero
_progress = 0;
notifyListeners();
/// The currently downloaded file as an array of bytes
List<int> bytes = [];
response.stream.listen(
/// = Closure listener for newly downloaded bytes
(List<int> newBytes) {
bytes.addAll(newBytes);
final downloadedLength = bytes.length;
if (contentLength == null) {
_progress = 0;
} else {
_progress = downloadedLength / contentLength;
}
notifyListeners();
print(
'Download in progress $_progress%: ${bytes.length} bytes so far');
},
/// = Download successfully completed
onDone: () async {
_state = DownloadState.downloaded;
notifyListeners();
/// The resulting local copy of the database
final file = await _getDownloadedZipFile();
// == Write to file
await file.writeAsBytes(bytes);
print('Download complete: ${bytes.length} bytes');
},
/// = Download error
onError: (e) {
_state = DownloadState.error;
_error = e.message;
print('Download error at $_progress%: $e');
},
cancelOnError: true,
);
}
// == Catches potential error
catch (e) {
_state = DownloadState.error;
_error = 'Could not download the databse: $e';
print('Download error at $_progress%: $e');
}
}
您的 startDownloading
函数 returns 在注册回调以侦听 Stream
并且不等待 Stream
完成后。
要等待 Stream
完成,您可以保存 .listen
返回的 StreamSubscription
,然后 await
来自 [=20] 的 Future
=]:
var streamSubscription = response.stream.listen(...);
await streamSubscription.asFuture();
我想编写一个线性的多阶段流程(如下所示),从文件下载开始,并有进度:
/// Processes the database, from download to prices processing.
Future<void> updateDatabase() async {
//final fontText = await File('./example/cosmic.flf').readAsString();
//print(art.renderFiglet('updateDatabase'));
// == 1) download
print('1 ======== DOWNLOADING ==========');
try {
await startDownloading();
} catch (err) {}
// == 2) Decompress: Whatever download was ok or not, we decompress the last downloaded zip file we have locally
print('2 ======== DECOMPRESSING ========');
try {
await startDecompressing();
} catch (err) {}
// == i) Stage i, etc.
但是在我的下载阶段有些东西不起作用,因为它开始阶段 2) 前期阶段 1) 完成。
我的第一阶段(下载)是这样的:
/// Starts download procress
Future<void> startDownloading() async {
print("startDownloading…");
_state = DownloadState.downloading;
_progress = 0;
notifyListeners();
/// Database string url
final databaseUrlForInstantData = "https://XXX";
try {
final request = Request('GET', Uri.parse(databaseUrlForInstantData));
final StreamedResponse response = await Client().send(request);
final contentLength = response.contentLength;
// == Start from zero
_progress = 0;
notifyListeners();
/// The currently downloaded file as an array of bytes
List<int> bytes = [];
response.stream.listen(
/// = Closure listener for newly downloaded bytes
(List<int> newBytes) {
bytes.addAll(newBytes);
final downloadedLength = bytes.length;
if (contentLength == null) {
_progress = 0;
} else {
_progress = downloadedLength / contentLength;
}
notifyListeners();
print(
'Download in progress $_progress%: ${bytes.length} bytes so far');
},
/// = Download successfully completed
onDone: () async {
_state = DownloadState.downloaded;
notifyListeners();
/// The resulting local copy of the database
final file = await _getDownloadedZipFile();
// == Write to file
await file.writeAsBytes(bytes);
print('Download complete: ${bytes.length} bytes');
},
/// = Download error
onError: (e) {
_state = DownloadState.error;
_error = e.message;
print('Download error at $_progress%: $e');
},
cancelOnError: true,
);
}
// == Catches potential error
catch (e) {
_state = DownloadState.error;
_error = 'Could not download the databse: $e';
print('Download error at $_progress%: $e');
}
}
您的 startDownloading
函数 returns 在注册回调以侦听 Stream
并且不等待 Stream
完成后。
要等待 Stream
完成,您可以保存 .listen
返回的 StreamSubscription
,然后 await
来自 [=20] 的 Future
=]:
var streamSubscription = response.stream.listen(...);
await streamSubscription.asFuture();