Sobes.tech
Middle

How are streams used in Flutter?

sobes.tech AI

Answer from AI

Streams in Flutter are used for handling sequences of asynchronous events. These can include data from the network, user input, state changes, etc.

Key aspects of usage:

  • Asynchronous programming: Streams are based on Future, but represent a stream of events rather than a single future value.
  • UI updates: Streams are often used to update the user interface in response to data changes without blocking the main thread.
  • Reactive programming: They form the basis for reactive approaches in state management (e.g., using BLoC or Provider with StreamProvider).

Main classes:

  • Stream: Represents a sequence of asynchronous events. You cannot create a Stream directly; it is created by a data source (e.g., HttpClient, File.watch, StreamController).
  • StreamController: Allows creating and managing streams. Used to add data or errors to the stream.
  • StreamSubscription: An object returned when subscribing to a stream. It allows listening to events and canceling the subscription.
  // Creating a stream via StreamController
  final _controller = StreamController<int>();

  // Adding data to the stream
  void addData(int data) {
    _controller.sink.add(data);
  }

  // Getting the stream for listening
  Stream<int> get stream => _controller.stream;

  // Closing the controller when no longer needed
  void dispose() {
    _controller.close();
  }

Usage examples:

  • Handling button press events: StreamController<void> _buttonClicked = StreamController();
  • Receiving data from WebSocket: _socket.listen((data) => _streamController.add(data));
  • Implementing timers: Stream<int> countStream = Stream.periodic(Duration(seconds: 1), (count) => count);

Widget integration:

  • StreamBuilder: A widget that rebuilds its subtree every time the stream emits a new value.
  StreamBuilder<int>(
    stream: countStream, // The same stream from the example above
    builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
      if (snapshot.hasError) {
        return Text('Error: ${snapshot.error}');
      }
      switch (snapshot.connectionState) {
        case ConnectionState.none:
          return Text('Select a number');
        case ConnectionState.waiting:
          return Text('Waiting...');
        case ConnectionState.active:
          return Text('${snapshot.data}'); // Displaying the current stream value
        case ConnectionState.done:
          return Text('${snapshot.data} (Closed)');
      }
    },
  )

Advantages:

  • Simplify asynchronous data processing.
  • Enable creating responsive user interfaces.
  • Are a key element of architectural patterns like BLoC.

It is important to manage the lifecycle of subscriptions (StreamSubscription.cancel()) and controllers (StreamController.close()) to prevent memory leaks.

How are streams used in Flutter? — Flutter - sobes.tech