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?
You can achieve this using percent_indicator package. On this link, it is already implemented to show download progress using percent_indicator.
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.
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.
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.
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.
Screenshot (Null Safe):
This solution
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),
),
),
),
);
}
}
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With