【问题标题】:How to await for the completion or error of an async download in Dart?如何等待 Dart 中异步下载的完成或错误?
【发布时间】:2021-09-05 05:46:12
【问题描述】:

我想写一个多阶段的线性过程(如下图),从文件下载开始,有进度:

  /// 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');
    }

  }

【问题讨论】:

    标签: dart async-await download


    【解决方案1】:

    您的startDownloading 函数在注册回调以侦听Stream 并且不等待Stream 完成后返回。

    要等待Stream完成,您可以保存.listen返回的StreamSubscription,然后保存await来自StreamSubscription.asFutureFuture

    var streamSubscription = response.stream.listen(...);
    await streamSubscription.asFuture();
    

    【讨论】:

    • 非常感谢。我补充说,一旦这样做,onDone 和 onError 永远不会被触发,您需要在 await 之后编写 on done 代码,而 on 错误代码必须位于 await 周围 try 的 catch 部分中
    • 我建议只使用await stream.forEach(...) 而不是使用listen 和订阅做体操。或者尽可能使用await for( ... in stream) { ... }
    猜你喜欢
    • 2019-11-29
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    • 2021-01-25
    • 2020-10-04
    • 2017-12-11
    • 2020-01-14
    相关资源
    最近更新 更多