Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Downloading progress in dart:http

I'm trying to make a progress bar indicator for a downloading file, but if I add a listener to the StreamedResponse, the piping works, but does to not finish its future.

final client = new http.Client();
http.StreamedResponse response = await client.send(http.Request("GET", Uri.parse('someurl')));

var received = 0;
var length = response.contentLength;

//if I remove this listener, the await below gets completed
var listen = response.stream.listen((List<int> bytes) {
  received += bytes.length;
  print("${(received / length) * 100} %");
});

var sink = downloadFile.openWrite();
await response.stream.pipe(sink);
listen.cancel();
sink.close();

On github they already advised someone that it was supposed to work, but on StreamedResponse docs stays that This should always be a single-subscription stream.. So, adding a listener to calculate the percentage seems to bugs StreamedResponse pipe in someway. Any idea on how to get this to work?

like image 495
Evaldo Bratti Avatar asked Jun 17 '19 20:06

Evaldo Bratti


1 Answers

@pskink comment let me to this solution that works for every type of sink you are using.

  var length = response.contentLength;
  var received = 0;
  var sink = downloadFile.openWrite();

  await response.stream.map((s) {
    received += s.length;
    print("${(received / length) * 100} %");
    return s;
  }).pipe(sink);

another way to accomplish this, if you are writing into a file, is to watch file length

  var length = response.contentLength;
  var sink = downloadFile.openWrite();

  Future.doWhile(() async {
    var received = await downloadFile.length();

    print("${(received / length) * 100} %");
    return received != length;
  });

  await response.stream.pipe(sink);
like image 87
Evaldo Bratti Avatar answered Oct 17 '22 08:10

Evaldo Bratti