Dart Tutorial

Dart Tutorial Single-Page Application Architecture Dart Features Dart Installation Guide Dart Basic Program Dart Syntax Dart Keywords Dart Variables Dart Comments Dart Standard Input Output Dart Important Concepts

Data Types

Built-in Data Types Numbers Strings Booleans Lists Sets Maps Runes and Graphemes Symbols Enumerations Constants Queues

Other data types

Objects Future and stream Iterable Miscellaneous types

OPERATORS

Precedence and associativity Arithmetic operators Equality and Relational operators Type Test Operators Assignment Operators Logical Operators Bitwise and Shift Operators Miscellaneous operators

Control Flow Statements

Introduction If statement If-else statement If-else-if statement Loops Switch and case Dart Break And Continue Assert In Dart

FUNCTIONS

Dart function Types of Functions Anonymous function main( ) function Lexical scope and closure Recursion Common Collection Methods

Object Oriented Concepts

Dart Object-Oriented Concepts Dart Classes Dart Constructors Dart This Keyword Dart Super Keyword Static Members Method Overriding Dart Interfaces Inheritance Dart Abstract Classes Dart Builder Classes Dart Callable Classes

Dart Type System

Dart Type System Dart Soundness Dart Type Inference

MISCELLANEOUS

Dart Isolates Dart Typedef Dart Metadata Dart Packages Dart Generics Dart Generators Dart Concurrency Dart Unit Testing Dart Html Dom Dart URIs Dart Extends, With and Implements Keywords Dart Optional Parameters Rust Vs Dart C++ vs Dart Golang Vs Dart Dart Basics Exception Handling

Dart Future and Stream

Before understanding Future and Stream in Dart, we need first to get familiar with two terms : Synchronous and Asynchronous Programming. 

In synchronous programming, a single operation is handled at a time, and the processing proceeds to the next operation only when the first one is completed. While in asynchronous programming, we can take up another task even if the previous one is not finished. 

Dart supports Asynchronous programming with the help of ‘Future’ and ‘Stream’ classes. 

Future refers to the processing that is left incomplete in-between. An asynchronous function returns Future that tells when the result will be ready. 

Stream refers to the sequence of asynchronous events which keep you informed of the next events in line. 

Future

Future represents the value or error that is supposed to be available in the Future. Handling such errors or values at the time they would be available, is mandatory and should be taken care of. 

Implementation = Future <data_type> class_name

They can basically exist in three states: 

  1. Uncompleted 
  2. Completed with a value
  3. Completed with an error 
Dart Future And Stream

Every Dart code that we write, a single thread is dedicated to picking events from the event queue and processing them for the program's execution.

Future Constructors

A Future constructor is a constructor that takes a function as the parameter and returns some value which can be Future or non - Future. In simple words, it creates a Future that contains the result of the process that calls that Future. 

The result can be one of the following options : 

  1. Throws = The Future returned is completed with an error. 
  2. Future itself = The Future returned is completed first, and then the completion of the created Future takes place. 
  3. Non – Future = The returned Future is completed with the value returned. 

Implementation =  factory Future( FutureOr <T> computation( ) ) ;

Properties 

  1. HashCode = 

Returns the hash code for a numerical value, and it returns the same value for int and doubles when the value provided is the same. 

Implementation = int get hashchode ;

  • Runtime Type =

Represents the type of runtime an object has. 

Implementation = Type get runtimeType ;

Methods

  • asStream( ) =

This method creates a stream that contains the result of the completion of the specified Future. If a Future remains incomplete, the stream would never be able to produce any events. While, if the Future is complete, the stream executes the event and eventually closes down. 

Implementation = Stream<T> asStream( ) ;

  • catchError( ) =

This method is used to handle all the errors that the Future emits. It returns a new completed Future with some result which could be of the Future or the call back ' onError '. The Future can complete with the following cases :

  • With a value = The Future returned is completed with this same value.
  • With an error = Test is called with the error value. In this case, the completion of Future depends on the Boolean value of the test :
  • True = The error calls the ' onError ', and with the result of this call, Future is executed. 
  • False = The exception is now not handled by ' catchError ' and the Future is made to complete with the same error. 
  • Omitted = The default value is true, and the function is supposed to always return true if the test is omitted. 

Implementation = 

Future<T> catchError (

          Function onError ,

                 { bool test (

                       Object error

                          ) ? }

               )
  • then< R > =

This method registers all the callbacks that have to be made as soon as the Future is completed. As we know by now, a future can complete with a value or an error; let us then understand how the method works in each case : 

  1. Completes with a value = The ' onValue ' callback will be called with the value with which the Future is completed. Depending upon the time of Future's completion, the callback is scheduled. If it is already completed, a callback won't be made immediately but would schedule for later. 
  2. Completes with an error = The ' onError ' callback will be called with the error with which the Future is completed. Remember that the ' onError ' callback must return a value or Future to complete the returned Future with either of these two.

Finally, it returns a Future that is completed with the results of the call to

‘ onValue ' or ' onError '. If the callback returns a Future, completion of Future returned by ' then ' would be completed with the same result as of the returned Future. Else if the callback throws, the returned Future is completed with the thrown error. 

If ' onError ' is not given, and this Future completes with an error, the error is forwarded directly to the returned Future.

Implementation = 

Future<R> then<R> (

             FutureOr<R> onValue (

                                 T value

                         ) ,

           { Function? onError }

) ;
  • toString( ) =

Converts a given number into an equivalent shortest string and returns the same. 

Implementation = external String toString( ) ;

  • whenComplete( ) =

This method registers a function to be called when this Future completes. Irrespective of whether a Future completes with a value or an error, the action function is called. Asynchronously, this is equivalent to the " finally " block. 

When this call is invoked, it returns a Future that would be completed in the same way as it was completed, unless an error occurs. If in case, the call does not return a Future, the value returned is ignored. And if it throws, the Future completes with that thrown error.

Let us say if the call returns another Future, then the Future returned previously is left in between until the completion of this another future. If this Future completes with an error, then the previous Future also completes with the same error. Remember that the value, as a result, is ignored. 

Implementation = 

Future<T> whenComplete (

      FutureOr<void> action (

) ;

Stream

Stream is a way by which we receive a sequence of events. These events can correspond to :

  1. Data event which is also known as the element of the stream.
  2. Error event which intimates if the event has failed. 

When the stream is done with emitting all the events, it notifies a single

' done ' event which signifies the end. We can use the listen( ) method with the function as a parameter to subscribe to the stream. 

We receive these events by an active object of the stream called as StreamSubscription object. Using this object, we can either entirely terminate the notification update of the event or temporarily pause it. 

Types of Streams 

  1. Single – subscription stream
  2. Broadcast stream

Single-subscription Stream

This stream enables only a single listener to receive the event. It starts emitting events only when the listener is active and stops generating them as soon as the listener unsubscribes. 

Remember that two listeners aren't allowed on a single-subscription stream even though the first one is cancelled. 

Broadcast Stream

This stream enables any number of listeners and notifies the events as soon as they are ready, irrespective of whether the listeners are available or not. They are mainly used for independent events. 

asBroadcastStream is used to enable several listeners to listen to a single subscription stream. 

By default, the streams are single-subscription streams. In the case of listening to a stream twice, the compiler throws an exception.

Stream Constructors 

  • Stream<T> constructor  =

This constructor is used to create a stream. 

Implementation = Stream( ) ; 

  • Stream.empty( ) =

This constructor is used to create an empty broadcast stream, and it performs a single task of sending ‘ done ’ events when the stream is listened to. 

Implementation = const factory Stream.empty( ) = _EmptyStream<T> ;

  • Stream.error( ) =

This constructor is used to create a stream that emits a single error before completing. Then it stackTrace and completes with a ‘ done ’ event. 

Implementation = 

Stream< T >.error (

Object error,

[ StackTrace? stackTrace ]

)

Stream Properties

  • First =

This property returns the first element of the given stream. As soon as the first element is retrieved, listening to this stream is stopped, by implicitly unsubscribing the method. 

There can be two cases of its working : 

  • The stream is empty = In this case, the Future returned by the stream completes with an error. 
  • Occurrence of some error event = In this case, the Future returned by the stream completes with that error. 

 Implementation = Future<T> get first { } 

  • hashCode =

Returns the hash code for a numerical value, and it returns the same value for int and doubles when the value provided is the same. 

Implementation = int get hashchode ;

  • isEmpty =

This property checks whether the given stream contains any elements or not and accordingly returns true or false. 

  • True = When the stream ends without emitting any elements, indicating that the stream is empty. 
  • False = When the stream emits an element. 

If the event causes an error, the future returned is completed with that error. 

Implementation = Future<bool> get isEmpty { }

  • Last =

This property returns the last element of the stream. In case of any error caused by the stream, the future returned is completed with that error. And if the stream is empty, the future returned completes with an error. 

Implementation = Future<T> get last { }

  • Length =

This property calculates the number of elements in the stream and returns the same. At the end of this stream, the future returned is completed with the number of elements calculated by this property. 

If, in any case, the stream causes an error, the future returned is completed with that error, terminating the processing. 

Implementation = Future<int> get length { }

  • runtimeType =

Represents the type of runtime an object has. 

Implementation = Type get runtimeType ;

  • single =

This property returns the single element of the given stream. If, in any case, the stream causes an error, the future returned is completed with that error, terminating the processing. 

If the stream is empty or has more than a single element, the future returned is completed with an error. 

Implementation = Future<T> get single { }

  • isBroadcast =

This property checks whether this stream is a broadcast stream or not and accordingly returns true or false. 

Implementation = bool get isBroadcast ;

Methods

  • any( ) =

This method checks whether ' test ' accepts any element provided by the stream. Here, we call ' test ' on each and every element of the stream to check the same. If it returns true, the future returned is completed with true. Else if the stream returns false, the future returned is completed with false. 

If, in any case, the stream causes an error or the call to test throws, the future returned is completed with that error. 

Implementation = 

Future<bool> any (

bool test (

             T element

)

           )
  • asBroadcastStream( ) =

This method returns a multi-subscription stream that produces the event as same as this. The stream returned will subscribe to this given stream.

Implementation = 

Stream<T> asBroadcastStream (

                { void onListen (

                    StreamSubscription<T> subscription

                              ) ? ,

                      void onCancel (

                   StreamSubscription<T> subscription

         ) ? }

)             
  • elementAt =

This method returns the value at the given index in the given stream. Listening to the stream is terminated as soon as the value at that index is retrieved. 

If, in any case, the stream causes an error before the value is retrieved, the Future returned is completed with the error. 

Implementation = 

Future<T> elementAt (

      int index

)
  • handleError( )

This method creates a wrapper Stream that determines some errors from this given stream. This generated wrapper stream sends the error to the ' test ' to match whether the errors are the same, and then the ' onError ' function determines this error. 

Implementation = 

Stream<T> handleError (

Function onError ,

{ bool test (

dynamic error

) ? }

)
  • listen( )

This method is used to subscribe the elements to the stream and then returns the StreamSubscription that handles the events emitted by the stream using the following handlers :

  • onData
  • onError
  • onDone

Implementation = 

StreamSubscription<T> listen (

          void onData (

                 T event

                    ) ? ,

             { Function? onError ,

                        void onDone (

                ) ? ,

             bool? cancelOnError }

)
  • toString( )

This method converts a given number into an equivalent shortest string and returns the same. 

Implementation = external String toString( ) ;

  • toList( )

This method collects all the elements of the given stream in the ' List '. It creates the List< T > and adds all the elements of the given stream to the list. At the end of the stream, the future returned is completed with the list. 

Implementation = Future< List<T> > toList( )