Reputation: 2248
I want to get the progress of a network image when I load it, but I found that the result of StreamBuilder
is not correct, but I can get the complete data using listen
.
This is my running code:
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Uri url = Uri.parse('https://s2.ax1x.com/2019/05/22/V9fCKH.jpg');
ImageChunkEvent loadingProgress;
http.Request get _req => http.Request('get', url);
@override
void initState() {
super.initState();
_init();
}
_init() async {
var _client = http.Client();
http.StreamedResponse r = await _client.send(_req);
if (r.statusCode == HttpStatus.ok) {
List<int> ds = [];
r.stream.listen((List<int> d) {
ds.addAll(d);
loadingProgress = ImageChunkEvent(
cumulativeBytesLoaded: ds.length,
expectedTotalBytes: r.contentLength,
);
}, onDone: () {
print(
'listen: $loadingProgress'); // listen: ImageChunkEvent#52717(cumulativeBytesLoaded: 8867, expectedTotalBytes: 8867)
_client?.close();
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: http.Client().send(_req),
builder: (context, AsyncSnapshot<http.StreamedResponse> snap) {
Widget result = SizedBox();
if (snap.hasData) {
List<int> ds = [];
ImageChunkEvent loadingProgress;
http.StreamedResponse r = snap.data;
return StreamBuilder(
stream: r.stream,
builder: (context, AsyncSnapshot<List<int>> s) {
if (s.hasData) {
ds.addAll(s.data);
loadingProgress = ImageChunkEvent(
cumulativeBytesLoaded: ds.length,
expectedTotalBytes: r.contentLength,
);
}
if (s.connectionState == ConnectionState.done) {
print(
'StreamBuilder :$loadingProgress'); // StreamBuilder :ImageChunkEvent#f7d34(cumulativeBytesLoaded: 1964, expectedTotalBytes: 8867)
return result;
}
return result;
},
);
}
return result;
},
),
);
}
}
In the above code, StreamBuilder
can't get the complete data, I don't know why, I hope someone can tell me, thank you.
Upvotes: 0
Views: 947
Reputation: 277047
StreamBuilder doesn't guarantee that builder
will be called for every single event.
It tries to call it at most once per frame.
As such, you shouldn't use StreamBuilder
to map the content of the stream into something else.
Upvotes: 1