Module 1
Topic 8

StreamProvider

Handling real-time data in Riverpod — working with streams, WebSockets, and continuous data updates.

Riverpod – StreamProvider Guide Dart – Streams Tutorial
What Is StreamProvider?

StreamProvider is a type of provider in Riverpod that holds a Stream . It's designed for real-time, continuous data flows like:

  • Firebase Firestore real-time updates
  • WebSocket connections
  • Sensor data (GPS, accelerometer)
  • Chat messages
  • Live stock prices
  • User presence status

✅ When to Use StreamProvider

Use StreamProvider when you need to listen to a continuous stream of data that updates over time. Unlike FutureProvider which returns a single value, StreamProvider emits multiple values over time.

Understanding Streams in Dart

A Stream is a sequence of asynchronous events. It's like a pipe that delivers data over time. There are two types of streams in Dart:

📡 Single-Subscription Stream

Can only be listened to once. The listener receives all events from the stream. Most common type.

📢 Broadcast Stream

Can be listened to by multiple listeners. Each listener receives the same events. Used for events that multiple parts of the app need to hear.

💡 Stream vs Future

  • Future – Emits a single value or error once
  • Stream – Emits multiple values over time
  • StreamProvider handles streams with loading and error states
Defining a StreamProvider

Defining a StreamProvider is similar to other providers, but the creation function returns a Stream .

Reading a StreamProvider

When you watch a StreamProvider , you get an AsyncValue that updates every time the stream emits a new value.

Step-by-Step Explanation
1.
Define the Provider messagesProvider is a StreamProvider that returns a stream of messages from a chat service.
2.
Watch the Provider ref.watch(messagesProvider) returns an AsyncValue that updates with each new value from the stream.
3.
Handle States – The .when() method handles loading, error, and data states. The data state receives the latest value from the stream.
4.
Automatic Updates – Whenever the stream emits a new value, the widget rebuilds with the new data.
StreamProvider with a Controller

Sometimes you need to control the stream manually, like sending data to a WebSocket or adding events to a stream. Here's how to use a StreamController with StreamProvider .

✅ Key Pattern

  • Provider holds the ChatNotifier instance
  • StreamProvider exposes the stream from the notifier
  • ref.watch(chatProvider) gives access to the notifier to send messages
  • ref.watch(messagesStreamProvider) listens for new messages
Complete Example: Timer App

Here's a complete example of a real-time timer app that uses StreamProvider with a periodic stream.

StreamProvider vs FutureProvider

StreamProvider

  • Multiple values over time
  • Real-time data updates
  • Continuous connection
  • Perfect for chat, sensors, notifications
  • Can be controlled with StreamController

FutureProvider

  • Single value once
  • One-time data fetch
  • Disconnected after completion
  • Perfect for API calls, database reads
  • Can be refreshed with ref.refresh()
Common Mistakes
❌ Mistake 1: Forgetting to dispose StreamController

If you create a StreamController , you must close it when it's no longer needed to prevent memory leaks.

✅ Correct: Dispose controllers properly

Use ref.onDispose or call dispose() in a StateNotifier to clean up controllers.

❌ Mistake 2: Using a single-subscription stream with multiple listeners

Single-subscription streams can only be listened to once. If multiple widgets try to listen, you'll get an error.

✅ Correct: Use broadcast streams for multiple listeners

Use StreamController.broadcast() when multiple widgets need to listen to the same stream.

❌ Mistake 3: Not handling the loading state

Like FutureProvider , StreamProvider has a loading state before the first value is emitted. Always handle it.

✅ Correct: Always handle loading, error, and data states

Use .when() or .maybeWhen() to handle all three states explicitly.

🎯 Key Takeaway

StreamProvider is the go-to solution for real-time data in Riverpod. It handles streams with loading and error states, automatically updates the UI when new data arrives, and works seamlessly with StreamController for manual control. Use it for any continuous data flow in your app.