Flutter: How to get upload / download progress for http requests
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.
Screenshot (Null Safe):
This solution
- Downloads an image from server.
- Shows downloading progress.
- 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),
),
),
),
);
}
}