Hi Guys, Welcome to Proto Coders Point.
In this Flutter Tutorial, We will learn what is flutter dart streams, How to use it in flutter app, and When to use flutter stream in app.
In Dart, Asynchronous programming is been characterized by Future & Streams.
In this Flutter Article let’s learn about dart streams.
What is a Stream in flutter dart?
A Dart Stream uses Asynchronous Programming concept, A Stream in dart is a sequence of asynchronous event that is been served to user, when any update occurs in data flow through Stream sink.
means, Instead of getting the next data or event manually by asking for it, The dart stream will automatically update the UI about the event, when it’s ready to be served.
Let’s Understand Stream in easiest way.
A Stream in nothing but a continuous async flow of data or event.
Here is a Animation on How data flow through stream in dart flutter.
A Data keep on flowing in stream during the life cycle of a stream.
There are 2 point which are associated to a Stream.
- Sink
- Source
1. Sink: In Flutter Streams, a Sink is a point from where we can add data into the stream pipe.
2. Source: In Flutter Stream, a Source is a point from where we can keep listening to stream data or get the data that is been added into the stream.
How to Create our own Stream in flutter.
Most of the tme, you’re going to working with dart streams, being created for you in background, when you use any extrenal libraries such as State Management (GetX, Bloc, Provider… and so on). But you can make your own stream by using StreamController in dart.
Let’s Create StreamController & add data to it using sink.add() (put stream)
//Create Stream StreamController _controller = StreamController(); int _counter = 60; // add event/data to stream controller using sink _controller.sink.add(_counter);
Listening to stream using StreamBuilder Widget
Now, we are done with creating stream & adding data into it, now we need to listen to the data coming into stream & print the data on the screen, so for that we are going to make use of StreamBuilder widget to listen to asynchronous event.
StreamBuilder(
initialData: _counter,
stream: _controller.stream,
builder: (context,snapshot){
return Text('${snapshot.data}');
}
),
Stream Basic – Example 1
Count Down Value using Stream in flutter
Flutter Streams Basic – Count Down using StreamController & StreamBuilder
Example 1: In this Flutter StreamController Example, We will simply build an app that can count down a value from n to 0 using stream Controller sink & update the UI.
Video Tutorial
main.dart
import 'dart:async'; import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: CounterApp() ); } } class CounterApp extends StatefulWidget { const CounterApp({Key? key}) : super(key: key); @override _CounterAppState createState() => _CounterAppState(); } class _CounterAppState extends State<CounterApp> { //create instance of streamcontroller class StreamController _controller = StreamController(); int _counter = 60; void StartTimer() async{ //Timer Method that runs every second Timer.periodic(Duration(seconds: 1), (timer) { _counter--; // add event/data to stream controller using sink _controller.sink.add(_counter); //will stop Count Down Timer when _counter value is 0 if(_counter<=0){ timer.cancel(); _controller.close(); } }); } @override void dispose() { // TODO: implement dispose super.dispose(); // Destroy the Stream Controller when use exit the app _controller.close(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ StreamBuilder( initialData: _counter, stream: _controller.stream, builder: (context,snapshot){ return Text('${snapshot.data}'); } ), SizedBox( height: 20, ), ElevatedButton(onPressed: (){ //start the timer StartTimer(); }, child: Text('Start Count Down')) ], ), ), ); } }
flutter Stream api – Example 2
Keep Fetching latest value of Crypto Currency using streams flutter
Dart Stream real time example – Fetch Crypto Currency price from API
Example 2: We will fetch data from Crypto Currency API & make use of flutter stream controller sink to add real time crypto currency data & update the UI using StreamBuilder widget.
As you know, Crypto Currency price/value keeps on changing very secondsm so crypto currency API is the best example to learn Flutter dart Stream.
Video Tutorial
API used:
https://api.nomics.com/v1/currencies/ticker?key=your_api_key&ids=BTC
The API gives us lot’s of JSON data of Crypto Currency, but we are using only 3 fields ‘name’, ‘logo_url’, ‘price’.
Note: flutter http package is need to added to make network call to API
DataModel.dart
As we are using only 3 field, Here is a datamodel with 3 field ‘name’, ‘image’, ‘price’. that help in storing data.
class DataModel{ String name; String image; String price; DataModel.fromJson(Map<String,dynamic> json) : name = json['name'], image=json['logo_url'], price=json['price']; //a method that convert object to json Map<String, dynamic> toJson() => { 'name': name, 'logo_url': image, 'price':price }; }
main.dart
import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stream_example/DataModel.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: HomePage() ); } } class HomePage extends StatefulWidget { const HomePage({Key? key}) : super(key: key); @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { //create stream StreamController<DataModel> _streamController = StreamController(); @override void dispose() { // stop streaming when app close _streamController.close(); } @override void initState() { // TODO: implement initState super.initState(); // A Timer method that run every 3 seconds Timer.periodic(Duration(seconds: 3), (timer) { getCryptoPrice(); }); } // a future method that fetch data from API Future<void> getCryptoPrice() async{ var url = Uri.parse('https://api.nomics.com/v1/currencies/ticker?key=your_api_key&ids=DOGE'); final response = await http.get(url); final databody = json.decode(response.body).first; DataModel dataModel = new DataModel.fromJson(databody); // add API response to stream controller sink _streamController.sink.add(dataModel); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: StreamBuilder<DataModel>( stream: _streamController.stream, builder: (context,snapdata){ switch(snapdata.connectionState){ case ConnectionState.waiting: return Center(child: CircularProgressIndicator(),); default: if(snapdata.hasError){ return Text('Please Wait....'); }else{ return BuildCoinWidget(snapdata.data!); } } }, ), ), ); } Widget BuildCoinWidget(DataModel dataModel){ return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text('${dataModel.name}',style: TextStyle(fontSize: 25),), SizedBox(height: 20,), SvgPicture.network('${dataModel.image}',width: 150,height: 150,), SizedBox(height: 20,), Text('\$${dataModel.price}',style: TextStyle(fontSize: 20,fontWeight: FontWeight.bold),) ], ), ); } }
output
Bitcoin price keep changing when API data get changed