Flutter:如何获取http请求的上传/下载进度

Jef*_*eff 4 dart flutter

我正在编写一个将图像上传到服务器的应用程序,我不希望仅显示微调框,而是希望能够获得该上传状态的进度。

此外,我想这样做而不使用Multipart表单数据。这是我当前正在使用的代码-但它似乎因管道中断而停滞了,对于是否将数据发送到服务器,我的反馈为零:

Future<String> _uploadFile(File assetFile) async {
  final url = <removed>;

  final stream = await assetFile.openRead();
  int length = assetFile.lengthSync();

  final client = new HttpClient();

  final request = await client.postUrl(Uri.parse(url));
request.headers.add(HttpHeaders.CONTENT_TYPE,  "application/octet-stream");
  request.contentLength = length;

  await request.addStream(stream);
  final response = await request.close();
  // response prociessing.
}
Run Code Online (Sandbox Code Playgroud)

是否可以将大数据作为流发送而无需将其读入内存,并且可以使用当前的dart / flutter API在上传中取得进展吗?

Cop*_*oad 13

屏幕截图(空安全):

在此处输入图片说明


这个解决方案

  1. 从服务器下载图像。
  2. 显示下载进度。
  3. 下载后,图像将保存到设备存储中。

代码:

import 'package:http/http.dart' as http;

class _MyPageState extends State<MyPage> {
  int _total = 0, _received = 0;
  late http.StreamedResponse _response;
  File? _image;
  final List<int> _bytes = [];

  Future<void> _downloadImage() async {
    _response = await http.Client()
        .send(http.Request('GET', Uri.parse('https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg')));
    _total = _response.contentLength ?? 0;

    _response.stream.listen((value) {
      setState(() {
        _bytes.addAll(value);
        _received += value.length;
      });
    }).onDone(() async {
      final file = File('${(await getApplicationDocumentsDirectory()).path}/image.png');
      await file.writeAsBytes(_bytes);
      setState(() {
        _image = file;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton.extended(
        label: Text('${_received ~/ 1024}/${_total ~/ 1024} KB'),
        icon: Icon(Icons.file_download),
        onPressed: _downloadImage,
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Center(
          child: SizedBox.fromSize(
            size: Size(400, 300),
            child: _image == null ? Placeholder() : Image.file(_image!, fit: BoxFit.fill),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 这似乎不适用于 http '0.13.4' 的网络 - 调用 `.send(http.Request('GET', ...` ) 似乎会下载整个文件,并且第一个也是唯一一个调用流包含所有文件数据。我在 github 上打开了一个问题:https://github.com/dart-lang/http/issues/631 (2认同)

Ric*_*eap 9

您已经在使用的Stream方式意味着您没有将整个文件读入内存。它可能以64k块的形式读取。

您可以使用StreamTransformer拦截生产者(文件)和消费者(HttpClient)之间的流,如下所示:

  int byteCount = 0;
  Stream<List<int>> stream2 = stream.transform(
    new StreamTransformer.fromHandlers(
      handleData: (data, sink) {
        byteCount += data.length;
        print(byteCount);
        sink.add(data);
      },
      handleError: (error, stack, sink) {},
      handleDone: (sink) {
        sink.close();
      },
    ),
  );
....
  await request.addStream(stream2);
Run Code Online (Sandbox Code Playgroud)

您应该看到byteCount以64k块递增。


Kai*_*Kai 8

尝试 dio库。该onSendProgress回调将是有益的。

例子:

response = await dio.post(
  "http://www.example.com",
  data: data,
  onSendProgress: (int sent, int total) {
    print("$sent $total");
  },
);
Run Code Online (Sandbox Code Playgroud)

参考:https : //github.com/flutterchina/dio/issues/103