flutterdartflutter-streambuilder

How to avoid flutter StreamBuilder skipping data?


It seems as if flutter StreamBuilder omits data if more than one data event occurs before the builder method gets executed.

I tried the following code which I expected to show "1;2;3;4;5;6;" etc. after pressing the button 3 times. (Shouldn't the builder method be called once for each ctrl.add() call?)

However, only every second ctrl.add() call reaches the builder method resulting in the output "2;4;6;".

Do I misunderstand the StreamBuilder behaviour? Or how can I fix the code so that multiple data can be sent "simultaneously"?

import 'dart:async';
import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  String _text = "";
  StreamController<int> ctrl = StreamController<int>();

  void _incrementCounter() {
    _counter++;
    ctrl.add(_counter);
    _counter++;
    ctrl.add(_counter);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: StreamBuilder(
        stream: ctrl.stream,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            _text += "${snapshot.data};";
          }
          return Text(_text);
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        child: const Icon(Icons.add),
      ),
    );
  }
}

Solution

  • OK, I found the answer in the flutter github issues pointing to the StreamBuilder documentation:

    The builder is called at the discretion of the Flutter pipeline, and will thus receive a timing-dependent sub-sequence of the snapshots that represent the interaction with the stream.

    So StreamBuilder just cannot be used if it is necessary to catch all data. :(

    I got rid of StreamBuilder now and use a ChangeNotifier instead.