januw a
januw a

Reputation: 2248

Flutter uses listen and StreamBuilder to subscribe to the same stream and get different results

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

Answers (1)

R&#233;mi Rousselet
R&#233;mi Rousselet

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

Related Questions