What Is Flutter Stream Use For

Michael PiperMichael Piper
3 min read

Streams in Flutter (and Dart) are a way to handle asynchronous data. They provide a continuous flow of data over time, which can be listened to and processed as it arrives. This is particularly useful for handling data from sources like network requests, user input events, and data updates in real-time applications.

Key Concepts of Streams

  1. Single-Subscription Streams:

    • Can have only one listener at a time.

    • Used when you want to handle a single sequence of events, like reading a file.

    void main() {
      Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);

      stream.listen((data) {
        print(data); // Output: 1, 2, 3, 4, 5
      });
    }
  1. Broadcast Streams:

    • Can have multiple listeners simultaneously.

    • Used for events that can be listened to by multiple parts of the app, like user interactions or real-time updates.

    void main() {
      Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]).asBroadcastStream();

      stream.listen((data) {
        print('Listener 1: $data'); // Output: Listener 1: 1, Listener 1: 2, ...
      });

      stream.listen((data) {
        print('Listener 2: $data'); // Output: Listener 2: 1, Listener 2: 2, ...
      });
    }
  1. StreamController:

    • Used to create a new stream and manage its listeners.

    • Can add data, error, and done events to the stream.

    import 'dart:async';

    void main() {
      final controller = StreamController<int>();

      controller.stream.listen((data) {
        print(data); // Output: 1, 2, 3, 4, 5
      });

      controller.add(1);
      controller.add(2);
      controller.add(3);
      controller.add(4);
      controller.add(5);
      controller.close();
    }
  1. Asynchronous Generators:

    • Functions that return a stream and use yield to provide data.
    Stream<int> asyncGenerator() async* {
      for (int i = 1; i <= 5; i++) {
        yield i;
      }
    }

    void main() {
      asyncGenerator().listen((data) {
        print(data); // Output: 1, 2, 3, 4, 5
      });
    }

Streams in Flutter

In Flutter, streams are commonly used for:

  • Handling user input (e.g., text field changes).

  • Fetching and updating data from a backend.

  • Managing state in reactive programming.

Example: StreamBuilder

StreamBuilder is a widget in Flutter that builds its content based on the latest snapshot of interaction with a stream. It automatically updates the UI when new data arrives.

import 'dart:async';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('StreamBuilder Example')),
        body: CounterScreen(),
      ),
    );
  }
}

class CounterScreen extends StatefulWidget {
  @override
  _CounterScreenState createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  final StreamController<int> _controller = StreamController<int>();
  int _counter = 0;

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

  @override
  void dispose() {
    _controller.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          StreamBuilder<int>(
            stream: _controller.stream,
            initialData: _counter,
            builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
              return Text('Counter: ${snapshot.data}');
            },
          ),
          SizedBox(height: 20),
          ElevatedButton(
            onPressed: _incrementCounter,
            child: Text('Increment'),
          ),
        ],
      ),
    );
  }
}

Summary

Streams in Dart and Flutter provide a powerful way to handle asynchronous data. They allow you to work with data that arrives over time, making it easier to build reactive and real-time applications. By using Stream, StreamController, and StreamBuilder, you can efficiently manage and update your app's state based on real-time data.

0
Subscribe to my newsletter

Read articles from Michael Piper directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Michael Piper
Michael Piper

Experienced Software Engineer skilled in creating mobile apps and web solutions. Expertise in iOS/Android app development, JavaScript frameworks, Python, and research methodologies. Detail-oriented problem solver with 10+ years of experience delivering top-notch solutions.