0
0
FlutterHow-ToBeginner · 3 min read

How to Use StreamBuilder in Flutter: Simple Guide

Use StreamBuilder in Flutter to build widgets that listen to a Stream and rebuild automatically when new data arrives. Provide the stream and a builder function that returns widgets based on the stream snapshot.
📐

Syntax

The StreamBuilder widget listens to a Stream and rebuilds its child widgets when the stream emits new data. It requires two main parts:

  • stream: The source of asynchronous data.
  • builder: A function that takes the current snapshot of the stream and returns a widget.
dart
StreamBuilder<T>(
  stream: yourStream, // The stream to listen to
  builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
    if (snapshot.hasData) {
      return Text('Data: ${snapshot.data}');
    } else if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    } else {
      return CircularProgressIndicator();
    }
  },
)
💻

Example

This example shows a StreamBuilder that listens to a stream emitting integers every second and displays the current count. It updates the UI automatically as new numbers arrive.

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final Stream<int> numberStream = Stream.periodic(
    Duration(seconds: 1),
    (count) => count,
  ).take(10); // Emits 0 to 9 every second

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('StreamBuilder Example')),
        body: Center(
          child: StreamBuilder<int>(
            stream: numberStream,
            builder: (context, snapshot) {
              if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              } else if (!snapshot.hasData) {
                return CircularProgressIndicator();
              } else {
                return Text('Current number: ${snapshot.data}', style: TextStyle(fontSize: 24));
              }
            },
          ),
        ),
      ),
    );
  }
}
Output
A screen with an app bar titled 'StreamBuilder Example' and centered text that updates every second showing 'Current number: 0', then 1, 2, ... up to 9.
⚠️

Common Pitfalls

  • Not handling null or no data: Always check snapshot.hasData before using snapshot.data to avoid errors.
  • Ignoring errors: Use snapshot.hasError to show error messages or fallback UI.
  • Recreating streams inside build: Define streams outside the build method to avoid restarting the stream on every rebuild.
dart
/* Wrong: recreating stream inside build causes stream to restart */
StreamBuilder<int>(
  stream: Stream.periodic(Duration(seconds: 1), (count) => count),
  builder: (context, snapshot) {
    // ...
  },
);

/* Right: define stream once outside build */
final myStream = Stream.periodic(Duration(seconds: 1), (count) => count);

StreamBuilder<int>(
  stream: myStream,
  builder: (context, snapshot) {
    // ...
  },
);
📊

Quick Reference

Remember these tips when using StreamBuilder:

  • Always check snapshot.hasData before accessing data.
  • Handle errors with snapshot.hasError.
  • Provide a loading widget when no data is available yet.
  • Define streams outside the build method to avoid restarting.

Key Takeaways

StreamBuilder rebuilds UI automatically when the stream emits new data.
Always check snapshot states: hasData, hasError, and connectionState.
Define streams outside the build method to prevent unwanted restarts.
Provide fallback widgets for loading and error states.
Use StreamBuilder to connect asynchronous data streams to your UI easily.