It provides an elegant and effectively ways to use stream in Provider.
StreamsProvider is a Flutter widget which provides a provider to its children via Provider.of<T>(context)
. It is used as a dependency injection (DI) widget so that a single instance of a provider can be provided to multiple widgets within a subtree.
In most cases, StreamsProvider
should be used to create new provider which will be made available to the rest of the subtree. In this case, since StreamsProvider
is responsible for creating the provider, it will automatically handle closing the provider.
StreamsProvider(
create: (BuildContext context) => ProviderA(),
child: ChildA(),
);
In some cases, StreamsProvider
can be used to provide an existing provider to a new portion of the widget tree. This will be most commonly used when an existing provider needs to be made available to a new route. In this case, StreamsProvider
will not automatically close the bloc since it did not create it.
StreamsProvider.value(
value: StreamsProvider.of<ProviderA>(context),
child: ScreenA(),
);
then from either ChildA, or ScreenA we can retrieve ProviderA with:
// with extensions
context.provider<ProviderA>();
// without extensions
StreamsProvider.of<ProviderA>(context)
StreamsSelector is a Flutter widget which select streams from a provider and invokes the builder in response to signal emits in the selector stream.
StreamsSelector<ProviderA, DataType>(
selector: (context, provider) {
// select streams from ProviderA
},
builder: (context, data, child) {
// return widget here based on selector stream emits
},
)
StreamsListener is a Flutter widget which takes a StreamsWidgetListener and a selector and invokes the listener in response to signal emits in the selector. It should be used for functionality that needs to occur once per signal emit such as navigation, showing a SnackBar, showing a Dialog, etc... listener is only called once for each signal emit.
StreamsListener<ProviderA, DataType>(
selector: (context, provider) {
// select streams from ProviderA
},
listener: (context, data) {
// do stuff here based on data changes
},
child: Container(),
)
Lets take a look at how to use StreamsSelector
to hook up a CounterPage
widget to a CounterProvider
.
class CounterProvider implements StreamsProvidable {
final _counter = MutableValueStream<int>(0);
ValueStream<int> counter => _counter;
void incrementCounter() {
_counter.value++;
}
void decrementCounter() {
_counter.value—;
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final CounterProvider counterProvider = context.provider<CounterProvider>();
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: StreamsSelector<CounterProvider, int>(
selector: (context, provider) => provider.counter,
builder: (context, count, child) {
return Center(
child: Text(
'$count',
style: TextStyle(fontSize: 24.0),
),
);
},
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
counterProvider.incrementCounter();
},
),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 5.0),
child: FloatingActionButton(
child: Icon(Icons.remove),
onPressed: () {
counterProvider.decrementCounter();
},
),
),
],
),
);
}
}