Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter: How to get upload / download progress for http requests

Tags:

flutter

dart

I am writing an app that uploads an image to a server, and instead of just showing a spinner, I'd love to be able to get progress on the status of that upload.

Additionally, I want to do this without using Multipart form data. This is the code I'm currently using - but it appears to be stalling out with a broken pipe, and I have zero feedback as to whether data is being sent to the server:

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.
}

Is it possible to send large data as a stream without reading it into memory, and can I get progress on that upload with current dart / flutter APIs?

like image 868
Jeff Avatar asked May 21 '18 19:05

Jeff


People also ask

How do I see download progress in flutter?

You can achieve this using percent_indicator package. On this link, it is already implemented to show download progress using percent_indicator.

What are get and POST HTTP requests in flutter?

Flutter - GET and POST http requests. To get dynamic data in a mobile application. We need to connect with a server to get and post some data. To achieve it, we always use HTTP to perform curl requests and create a connection between applications and server at a certain period to send or receive the data request from an application to the server.

How do I get dynamic data in flutter?

Flutter - GET and POST http requests To get dynamic data in a mobile application. We need to connect with a server to get and post some data. To achieve it, we always use HTTP to perform curl requests and create a connection between applications and server at a certain period to send or receive the data request from an application to the server.

How do I create a new application in flutter?

Once you have your environment set up for Flutter, you can run the following to create a new application: In this example, you will be connecting to JSON Placeholder. This code uses the package’s If that request was successful, this code will return a List<Post> using Post.fromJson. Otherwise, an error message is thrown.

How do I get the location of a file in flutter?

The _getFile () method finds an appropriate place on the user’s device to put the file. In this case we are choosing to use the documents directory. You could also chose the temp directory or somewhere else. This method is using the path_provider package to get that location. Note that we are making a choice here about our Flutter app.


3 Answers

Screenshot (Null Safe):

enter image description here


This solution

  1. Downloads an image from server.
  2. Shows downloading progress.
  3. After download, the image is saved to device storage.

Code:

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),
          ),
        ),
      ),
    );
  }
}
like image 167
CopsOnRoad Avatar answered Oct 16 '22 23:10

CopsOnRoad


The way that you are already using Stream means that you are not reading the whole file into memory. It's being read in as, probably, 64k chunks.

You could intercept the stream between the producer (File) and consumer (HttpClient) with a StreamTransformer, like this:

  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);

You should see byteCount incrementing in 64k chunks.

like image 13
Richard Heap Avatar answered Oct 17 '22 00:10

Richard Heap


Try dio library. The onSendProgress callback would be helpful.

example:

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

Reference: https://github.com/flutterchina/dio/issues/103

like image 11
Kai Avatar answered Oct 17 '22 00:10

Kai