flutter_multi_stream_builder
A Flutter widget that efficiently handles multiple streams in a single widget tree, eliminating the need for nested StreamBuilder widgets.
Features
✨ Multiple Stream Support - Handle any number of streams simultaneously
🔒 Type Safety - Full generic type support for each stream
⚡ Efficient Rebuilding - Only rebuilds when any of the streams emit new data
🎯 Clean API - Simple builder pattern similar to StreamBuilder
🔄 Flutter Integration - Seamlessly integrates with existing Flutter applications
Getting Started
Installation
Add this package to your pubspec.yaml:
dependencies:
flutter_multi_stream_builder: ^1.0.0
Then run:
flutter pub get
Basic Usage
import 'package:flutter_multi_stream_builder/flutter_multi_stream_builder.dart';
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiStreamBuilder(
streams: {
userStream,
settingsStream,
notificationsStream,
},
builder: (getSnapshot) {
final userSnapshot = getSnapshot(userStream);
final settingsSnapshot = getSnapshot(settingsStream);
final notificationsSnapshot = getSnapshot(notificationsStream);
if (userSnapshot.hasData &&
settingsSnapshot.hasData &&
notificationsSnapshot.hasData) {
return UserProfileWidget(
user: userSnapshot.data!,
settings: settingsSnapshot.data!,
notifications: notificationsSnapshot.data!,
);
}
if (userSnapshot.hasError ||
settingsSnapshot.hasError ||
notificationsSnapshot.hasError) {
return ErrorWidget('Something went wrong');
}
return CircularProgressIndicator();
},
);
}
}
Advanced Usage
Handling Different Stream Types
You can handle streams of different types in the same builder:
MultiStreamBuilder(
streams: {userStream, counterStream, messageStream},
builder: (getSnapshot) {
final user = getSnapshot(userStream).data as User?;
final count = getSnapshot(counterStream).data as int?;
final messages = getSnapshot(messageStream).data as List<Message>?;
return Column(
children: [
if (user != null) UserCard(user: user),
if (count != null) CounterDisplay(count: count),
if (messages != null) MessageList(messages: messages),
],
);
},
)
Error Handling
Check for errors on individual streams:
final userSnapshot = getSnapshot(userStream);
if (userSnapshot.hasError) {
return ErrorWidget('Failed to load user: ${userSnapshot.error}');
}
Loading States
Handle different loading states:
MultiStreamBuilder(
streams: {dataStream, configStream},
builder: (getSnapshot) {
final dataSnapshot = getSnapshot(dataStream);
final configSnapshot = getSnapshot(configStream);
// Check if any stream is still loading
if (dataSnapshot.connectionState == ConnectionState.waiting ||
configSnapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
// Check if any stream has an error
if (dataSnapshot.hasError || configSnapshot.hasError) {
return ErrorWidget('Failed to load data');
}
// All streams have data
return MyWidget(
data: dataSnapshot.data!,
config: configSnapshot.data!,
);
},
)
Comparison with Nested StreamBuilder
Before (Nested StreamBuilder)
StreamBuilder<User>(
stream: userStream,
builder: (context, userSnapshot) {
return StreamBuilder<Settings>(
stream: settingsStream,
builder: (context, settingsSnapshot) {
return StreamBuilder<List<Notification>>(
stream: notificationsStream,
builder: (context, notificationsSnapshot) {
// Complex nested logic here
if (userSnapshot.hasData &&
settingsSnapshot.hasData &&
notificationsSnapshot.hasData) {
return UserProfileWidget(
user: userSnapshot.data!,
settings: settingsSnapshot.data!,
notifications: notificationsSnapshot.data!,
);
}
return CircularProgressIndicator();
},
);
},
);
},
)
After (MultiStreamBuilder)
MultiStreamBuilder(
streams: {userStream, settingsStream, notificationsStream},
builder: (getSnapshot) {
final userSnapshot = getSnapshot(userStream);
final settingsSnapshot = getSnapshot(settingsStream);
final notificationsSnapshot = getSnapshot(notificationsStream);
if (userSnapshot.hasData &&
settingsSnapshot.hasData &&
notificationsSnapshot.hasData) {
return UserProfileWidget(
user: userSnapshot.data!,
settings: settingsSnapshot.data!,
notifications: notificationsSnapshot.data!,
);
}
return CircularProgressIndicator();
},
)
API Reference
MultiStreamBuilder
A widget that builds itself based on the latest snapshots of multiple streams.
Constructor
const MultiStreamBuilder({
Key? key,
required Set<Stream> streams,
required Widget Function(AsyncSnapshot<T> Function<T>(Stream<T>) getSnapshot) builder,
})
Parameters
-
streams (
Set<Stream>) - The set of streams to listen to. Each stream in this set will be listened to and its snapshots will be available in the builder function. -
builder (
Widget Function(AsyncSnapshot<T> Function<T>(Stream<T>) getSnapshot)) - The builder function that creates the widget tree. This function is called whenever any of the streams emit new data.
Example
MultiStreamBuilder(
streams: {stream1, stream2, stream3},
builder: (getSnapshot) {
final snapshot1 = getSnapshot(stream1);
final snapshot2 = getSnapshot(stream2);
final snapshot3 = getSnapshot(stream3);
if (snapshot1.hasData && snapshot2.hasData && snapshot3.hasData) {
return Text('All streams have data!');
}
return CircularProgressIndicator();
},
)
Performance Considerations
- The widget efficiently manages stream subscriptions and only rebuilds when necessary
- Each stream is handled independently, so partial updates are possible
- The builder function is called whenever any stream emits new data
- Consider using
Stream.periodicor other continuous streams carefully
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Additional Information
- Documentation: API Reference
- Issues: GitHub Issues
- Source Code: GitHub Repository
For more examples, see the /example folder in the package repository.
Libraries
- flutter_multi_stream_builder
- A Flutter package that provides a
MultiStreamBuilderwidget for efficiently handling multiple streams in a single widget tree.