Flutter Streams

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