The Google I/O 2018 video about Flutter explains how to use Dart streams to manage state in a Flutter application. The speaker talked about using Sink as input stre
A StreamSink is a StreamConsumer, which means it can take several streams (added by addStream) and processes the events these streams emit.
If it is the StreamSink of a StreamController then all events from the added streams are emitted by the stream created by the StreamController.
This way you can pipe (forward) one or more streams into another one.
If you are looking for a very basic definitions on stream and sinks, then refer to this:
Stream - the conveyor belt is called as a stream
StreamController - this is what controls the stream
StreamTransformer - this is what processes the input data
StreamBuilder - it’s a method that takes stream as an input and provides us with a builder which rebuilds every time there is a new value of a stream
sink - the property which takes an input
stream - the property which gives the output out of the Stream
For more details, please refer to this article
Let us take a simple example of SINKS & STREAMS in Flutter. Please Reade the comments
class LoginBloc {
final _repository = Repository();
final _loginResponse = BehaviorSubject<bool>(); //---->> a simple Sink
Stream<bool> get isSuccessful => _loginResponse.stream; //-----> Stream linked with above sink
/*
* Below is an async function which uses Repository class
* to hit a login API and gets the result in a variable
* isUserLoginSuccessful[true/false]. and then Add the result
* into the sink.
* now whenever something is added to the sink, a callback is given to
* the stream linked to that Sink, which is managed by the framework itself
*
*/
Future getLoginResponse() async {
bool isUserLoginSuccessful = await _repository.processUserLogin();
_loginResponse.sink.add(isUserLoginSuccessful);
}
dispose() {
_loginResponse.close();
}
}
Now, I am using this LoginBloc in Login Screen.
class Login extends StatelessWidget {
final LoginBloc loginBloc; // ----> Here is the Object of LoginBloc
Login(this.loginBloc);
void _onClickLoginButton() async {
// Hit login API
// fetch Login API response data
loginBloc.getLoginResponse(); //------> here is the function we are using in Login
}
@override
Widget build(BuildContext context) {
return StreamBuilder<bool>( // ----> You need to use a StreamBuilder Widget on the top Root, or according to the Business logic
stream: loginBloc.isSuccessful, // ----> here is the stream which is triggered by Sink which is linked by this stream
builder: (context, snapshot) {
// DO WHATEVER YOU WANT AFTER CALLBACK TO STREAM
});
i hope this may make your stream & sink concept more clearer.
Sink and Stream both are parts of the StreamController. You add a data to the StreamController using Sink which can be listened via the Stream.
Example:
final _user = StreamController<User>();
Sink get updateUser => _user.sink;
Stream<User> get user => _user.stream;
Usage:
updateUser.add(yourUserObject); // This will add data to the stream.
Whenever a data is added to the stream via sink, it will be emitted which can be listened using the listen method.
user.listen((user) => print(user));
You can perform a various number of actions before the stream is emitted. transform method is an example which can be used to transform the input data before it gets emitted.