StreamProvider
StreamProvider seamlessly integrates Dart Streams into your Flutter applications.
StreamProvider is ideal for data that produces values over time. It wraps the underlying Stream in an AsyncValue, allowing you to gracefully handle loading and error states without using StreamBuilder.
When to Use StreamProvider
- Listening to WebSocket events or Server-Sent Events (SSE)
- Real-time database updates like Firebase Firestore or Supabase
- Location updates or sensor data
Basic Syntax
Simply return a Stream from a function annotated with @riverpod:
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'location.g.dart';
@riverpod
Stream<Location> userLocation(UserLocationRef ref) async* {
final service = ref.watch(locationServiceProvider);
yield* service.getLocationStream();
}Using StreamProvider in Widgets
StreamProvider yields an AsyncValue just like FutureProvider, so you can use.when() to render different UI states:
class LocationTracker extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final locationAsync = ref.watch(userLocationProvider);
return locationAsync.when(
data: (location) => Text('Lat: ${location.lat}, Lng: ${location.lng}'),
loading: () => CircularProgressIndicator(),
error: (error, stack) => Text('Error getting location: $error'),
);
}
}Converting Streams to Futures
You can listen to the latest state synchronously or get the next emitted event by appending .future:
ElevatedButton(
onPressed: () async {
// Wait for the next location emitted by the stream
final nextLocation = await ref.read(userLocationProvider.future);
print(nextLocation);
},
child: Text('Get current location'),
)