You are on page 1of 93

C:\android-sdk\cmdline-tools\tools;C:\android-sdk\cmdline-tools\tools\bin;C:\android-

sdk\cmdline-tools\platform-tools;

Native and Non-Native Compilers


A native compiler converts the source program into machine code for the platform
on which it runs. The code will not require any translation to be interpreted and
executed by the CPU. A non-native compiler converts the source program into a
more general format where it can be run on multiple platforms. The code will require
translation to be interpreted and executed by the CPU.

Early Cross-Platform Development Tools


Anyway, Silicon Valley soon realized what a problem this was and set to work on
developing tools for cross-platform mobile application development. They quickly
split into two groups of development tools: those that used native libraries and those
that didn’t.

Development Tools That Used Native Libraries


These tools created a ‘Unified’ API on top of the native SDK supplied by Apple and
Google. Many of these development tools, for example Xamarin, Appcelerator,
Nativescript are still around. A unified API provides an abstraction layer that
consolidates multiple third-party APIs into a single set of data models accessed
through common API endpoints. ... The goal of a unified API is to reduce the time it
takes to complete integrations with multiple similar applications to meet a common
use case.

Unified API Does Not Cover 100%


The problem with these types of applications is that the ‘Unified API’ does not cover
100% and leaves the developers with many burdens, such as having to still write a
large chunk of platform specific code.

Use Widget SDKs


Also, these apps use the Widgets from the SDKs. Therefore, the apps can look
different because they use different Widgets from different SDKs for different
platforms.

Development Tools That Didn’t Use Native Libraries


These tools took a different approach. Most of these attempted to bypass the SDK
approach and write code that runs on the platform’s browser. This had the
advantage of being able to use many of the HTML5 and JavaScript capabilities
already built-in. The app would run in a ‘web view’. A “webview” is a browser
bundled inside of a mobile application producing what is called a hybrid app. Using a
webview allows mobile apps to be built using Web technologies (HTML, JavaScript,
CSS, etc.) but still package it as a native app and put it in the app store. The
problem with these types of applications is speed. They are not running natively in
compiled machine code, they are running on a hidden web browser. Many of these
development tools, for example Cordova, PhoneGap are still around.

Modern Cross-Platform Development Tools


More recently, two main rivals have emerged and look to be leading the field of
mobile app development tools: Facebook React Native and Google Flutter.

React Native
React.JS is an excellent JavaScript framework that has been popular for years and
works with both mobile and non-mobile websites equally well. Developers write user
interfaces with Component objects, like lego blocks. These Components can contain
code so that they can react to the user’s input and produce an interactive user
interface. React Native is like React, but it uses native components instead of web
components as building blocks.

How Does It Work?


React Native runs in two parts.
1. The UI.
It displays the ui and receives user input.
2. The JavaScript engine.
It interprets and executes the JavaScript application code.

The two parts communicate with a bridge.


React native apps are not completely native compiled. A lot of the deployed code is
native but your part of the app runs as embedded JavaScript, communicating
through a bridge with the native components. This is not the optimum solution for
performance.
Google Flutter
Google Flutter has only been available since 2017 but it is making waves because it
takes a different approach to crossplatform mobile app development. Google is
currently working on the successor to its Android operating system called Fuchsia
and it is writing it using Flutter. So, Flutter is very important to Google. You write
user interfaces using Google Flutter user interface widgets, not the native iOS or
Android UI widgets shipped with their retrospective SDKs. A Flutter app made using
Flutter Widgets will look exactly the same on iOS as it does on Android because it
will use the same Widgets from the same library. Flutter comes with many widgets,
including those that mimic Google’s Material look & feel and those that mimic Apples
iOS look & feel.

Google Flutter uses its own high-performance rendering engine to draw these
widgets and they have been designed to work on all mobile platforms. Also, these
widgets are extendable. You write the application code in Google’s Dart language
and it is compiled ahead-of-time into machine-code for native-like performance, thus
offering a performance advantage over React Native.
There is no bridge between the user interface and the application code.
DART
Platforms
Unlike conventional languages, Dart has been optimized to be deployed to run on a
variety of platforms:
1. Within a web browser as JavaScript
2. As an interpreted application
3. As a native application

1. Within a Web Browser


Dart provides an SDK, which provides command-line tools to transpile Dart source
code into JavaScript. This has been developed so efficiently that the resulting
transpiled JavaScript is more efficient than its hand-coded equivalent!

2. As Interpreted Application
The Dart SDK includes a Virtual Machine. A virtual machine is a sandbox in which
code may run without directly communicating with the underlying operating system.
This enables Dart code to be invoked from the command-line, using the ‘dart’
command-line tool in the SDK. This code is compiled on demand just-in-time as it
runs. Using Dart in this way is a great way to write server-side applications and it
performs at a similar level to Java / .Net.
The name "Dart VM" is historical. Dart VM is a virtual machine in a sense that it provides an
execution environment for a high-level programming language, however it does not imply that
Dart is always interpreted or JIT-compiled, when executing on Dart VM. For example, Dart code
can be compiled into machine code using Dart VM AOT pipeline and then executed within a
stripped version of the Dart VM, called precompiled runtime, which does not contain any
compiler components and is incapable of loading Dart source code dynamically.
A sandbox is an isolated testing environment that enables users to run programs or execute files
without affecting the application, system or platform on which they run. Software developers
use sandboxes to test new programming code.

Hot Reloading / Hot Replacing


If the developer is running the Dart application in the Dart virtual machine from the
command-line (interpreted), the JIT compiler can reload the code when the
underlying source code changes, often while preserving the application state
(variables) whenever possible. So, the developer can write and run the code at
almost the same time. This makes application development very fast indeed. Yet at
the end of the development process, the code can be compiled using the ahead-of-
time compiler and deployed as a native application.

An interpreted language is a type of programming language for which most of its


implementations execute instructions directly and freely, without previously compiling a program
into machine-language instructions

Flutter Development (Debug Mode)


When you are developing a Flutter Application, most of the time you run it in Debug
Mode and the code is JIT compiled & interpreted. This mode is known as ‘check’ or
‘slow’ mode. Under this mode, the assertion functions, including all debugging
information, service extensions, and debugging aids such as “observatory,” are
enabled. This mode is optimized for rapid development and operation, but not for
execution speed, package size, or deployment. Once your app is written you can
build it to run in Release Mode as a native application and it will perform much
better.

3. As Native Application
Dart code can be compiled ahead-of-time so that the code may be deployed as
machine-code. Flutter was mostly written using Dart and runs natively. This makes
Flutter fast, as well as customizable (as the Flutter widgets were written in Dart).

A compiler creates the binary code from Dart source code. For mobile applications the source
code is compiled for multiple processors ARM, ARM64, x64 and for both platforms - Android and
iOS. This means there are multiple resulting binary files for each supported processor and
platform combination.
The concept of source code and compilation to a target platform is basically the same for each
programming language. JIT (Just in Time) compiles at runtime on-the-fly while AOT (Ahead of
Time) compiles before the application is deployed and launched.
Swift can compile to native code and to Java bytecode. Swift is AoT while Java is JiT. The end
result is always binary code for the target platform and CPU.

Dart SDK
The Dart SDK comprises of three main elements:
1. Command-line tools.
2. Command-line compilers.
3. Libraries.

1. Command-Line Tools
The Dart SDK contains the following command line tools:
Name Description
dart Enables you to execute a .dart file within the Dart Virtual Machine.
dart2js Compiles dart source code to JavaScript.
dartanalyser Analyses dart source code. This is used by many of the code editors
to provide error and warning highlighting.
dartdevc Compiles dart source code to JavaScript. Similar to dart2js except that it
supports incremental compilation, which lends itself to developers.
dartdoc Generates Dart documentation from source code. As the seminal book
‘Domain-Driven Design’ by Eric Evans states: ‘the code is the model and the model
is the code’.
dartfmt Formats Dart source code. This is used by many of the code editors to
provide Dart formatting.
pub This is Google’s Package Manager.

2. Command-Line Compilers
Dartium, WebDev and Build_Runner
You can run Dart in a browser called Dartium without compiling it to JavaScript.
Dartium is basically Chrome with a Dart VM. However, the mainstream Dart web
development route is now writing the code with Dart but compiling and running as
JavaScript using the dart2js and dartdevc JavaScript compilers in combination with
the webdev and build_runner utilities.

Dart2js and DartDevC


These two JavaScript compilers have different use cases. Normally these are used
with the tool webdev and you don’t usually have to worry about which compiler
you’re using, because it chooses the right compiler for your use case. When you’re
developing your app, webdev chooses dartdevc, which supports incremental
compilation so you can quickly see the results of your edits. When you’re building
your app for deployment, webdev chooses dart2js, which uses techniques such as
tree shaking to produce optimized code.

3. Libraries
Name Description
dart:core Built-in types, collections, and other core functionality. This library is
automatically imported into every Dart program.
dart:async Support for asynchronous programming, with classes such as Future
and Stream.
dart:math Mathematical constants and functions, plus a random number generator.
dart:convert Encoders and decoders for converting between different data
representations, including JSON and UTF-8.

Introduction to Typing
Typically, computer languages have fallen into two camps:
1. Statically-typed languages.
2. Dynamically-typed languages.
1. Statically-typed languages.
These languages have specific variable types and the developer compiles the code
using an ‘ahead-of-time’ compiler. The compiler type checking is performed before
the code is run. This is an excellent way to develop software as the compiler
performs staticanalysis of the code as part of the compilation, alerting the developer
when issues arise. Software typically takes longer to develop in this method, but the
software developed in this manner typically works better in complex scenarios.

2. Dynamically-typed languages.
These languages don’t have specific variable types and no ahead-of-time
compilation is performed. Dynamically-typed languages make the development
process very quick as the developer does not typically need to recompile the code.
However, code developed in this manner tends to lend itself to simpler
scenarios as it can be more error-prone.

Dart Typing
Dart is different because Dart code can be run with both static types and dynamic
type variables.

Dart performs type checking at two different times:


When the code is compiled (code is reloaded / or compiled ahead-of-time).
When the code is run (runtime).

Static Types
These are the most-commonly used and built-in Dart types:
Type Description
int Integers (no decimals).
double Decimal number (double precision).
bool Boolean true or false.
String Immutable string.
StringBuffer Mutable string.
RegExp Regular expressions.
List, Map, Set Dart provides Collection classes.
DateTime A point in time.
Duration A span of time.
Uri Uniform Resource Identifier
Error Error information

int double and boolean are primitive(belonging to an early stage of technical development) data
types in dart which have their own classes (Integer, Boolean & Double) that’s why they starts with
lower case letter.

Dynamic Types (aka Untyped)


You can define untyped variables by declaring them using the ‘var’ or ‘dynamic’
keywords. The ‘var’ keyword declares a variable without specifying its type, leaving
the variable as a dynamic. The ‘dynamic’ keyword declares a variable of the type
‘dynamic’ with optional typing.

There is a difference, but it is subtle.


void main() {
print (multiplyMethod1(2,4));
print (multiplyMethod2(2,4));
}
dynamic multiplyMethod1(int a, int b){
return a * b;
}
var multiplyMethod2(int a, int b){
return a * b;
}

This code won’t compile. Dartpad displays the following error:


Error compiling to JavaScript: main.dart:10:1: Error: The return type can't be 'var'.
var multiplyMethod2(int a, int b){ ^^^ Error: Compilation failed. This is because
methods need to return a type and a ‘var’ does not specify a type.

Raw Strings
In Dart, normally you can add escape characters to format your string. For example:
‘\n’ means ‘new line’. However, you can prefix the string with an ‘r’ to indicate to tell
Dart to treat the string differently, to ignore escape characters.
Example Code – ‘New Lines’:
main(){
print('this\nstring\nhas\nescape\ncharacters');
print('');
print(r'this\nstring\nhas\nescape\ncharacters');
}
Output
this
string
has
escape
characters

this\nstring\nhas\nescape\ncharacters

Example Code – ‘Dollar Sign’:


void main() {
double price = 100.75;
print('Price is: \$${price}');
}
Output
Price is: $100.75

Runes
Runes are also special characters encoded into a string.
Here is a link with a lot of the run codes:
https://www.compart.com/en/unicode/block/U+1F300

Example Code
main() {
var clapping = '\u{1f44f}';
print(clapping);
}
Output
􀬛􀬛
Important Dart Concepts

Final and const


If you never intend to change a variable, use final or const, either instead of var or in
addition to a type. A final variable can be set only once; a const variable is a
compile-time constant. (Const variables are implicitly final.) A final top-level or class
variable is initialized the first time it’s used.

Note: Instance variables can be final but not const. Final instance variables must be


initialized before the constructor body starts — at the variable declaration, by a
constructor parameter, or in the constructor’s initializer list.
Here’s an example of creating and setting a final variable:

final name = 'Bob'; // Without a type annotation


final String nickname = 'Bobby';

You can’t change the value of a final variable:


name = 'Alice'; // Error: a final variable can only be set once.

Use const for variables that you want to be compile-time constants. If the const


variable is at the class level, mark it static const. Where you declare the variable, set
the value to a compile-time constant such as a number or string literal, a const
variable, or the result of an arithmetic operation on constant numbers:

const bar = 1000000; // Unit of pressure (dynes/cm2)


const double atm = 1.01325 * bar; // Standard atmosphere

The const keyword isn’t just for declaring constant variables. You can also use it to
create constant values, as well as to declare constructors that create constant
values. Any variable can have a constant value.

var foo = const [];


final bar = const [];
const baz = []; // Equivalent to `const []`

You can omit const from the initializing expression of a const declaration, like


for baz above.
You can change the value of a non-final, non-const variable, even if it used to have
a const value:

foo = [1, 2, 3]; // Was const []


You can’t change the value of a const variable:
baz = [42]; // Error: Constant variables can't be assigned a value.

Main(){
var mylist = const[1,2,3];
mylist[0] = 7; // not allowed, you can’t change single element in the list
mylist = [4,5,6]; // is allowed, you can change the whole list.
print(mylist);
}

As of Dart 2.5, you can define constants that use type checks and
casts (is and as), collection if, and spread operators (... and ...?):
// Valid compile-time constants as of Dart 2.5.
const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; // Use a typecast.
const map = {if (i is int) i: "int"}; // Use is and collection if.
const set = {if (list is List<int>) ...list}; // ...and a spread.

"static", "final", and "const" mean entirely distinct things in Dart:

"static" means a member is available on the class itself instead of on instances of


the class. That's all it means, and it isn't used for anything else. static modifies
*members*.

"final" means single-assignment: a final variable or field *must* have an initializer.


Once assigned a value, a final variable's value cannot be changed. final modifies
*variables*.

"const" has a meaning that's a bit more complex and subtle in Dart. const modifies


*values*. You can use it when creating collections, like const [1, 2, 3], and when
constructing objects (instead of new) like const Point(2, 3). Here, const means that
the object's entire deep state can be determined entirely at compile time and that the
Object will be frozen and completely immutable.

Const objects have a couple of interesting properties and restrictions:

1. They must be created from data that can be calculated at compile time. A
const object does not have access to anything you would need to calculate at
runtime. 1 + 2 is a valid const expression, but new DateTime.now() is not. 
2. They are deeply, transitively immutable. If you have a final field containing a
collection, that collection can still be mutable. If you have a const collection,
everything in it must also be const, recursively. 
3. They are *canonicalized*. This is sort of like string interning: for any given
const value, a single const object will be created and re-used no matter how
many times the const expression(s) are evaluated. In other words: 

getConst() => const [1, 2]; 


main() { 
  var a = getConst(); 
  var b = getConst(); 
  print(a === b); // true 

I think Dart does a pretty good job of keeping the semantics and the keywords nicely
clear and distinct. (There was a time where const was used both for const and final.
It was confusing.) The only downside is that when you want to indicate a member
that is single-assignment and on the class itself, you have to use both keywords:
static final.

Here’s how you turn a string into a number, or vice versa:

// String -> int


var one = int.parse('1');
assert(one == 1);

// String -> double


var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);

// int -> String


String oneAsString = 1.toString();
assert(oneAsString == '1');

// double -> String


String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');

Lists

Perhaps the most common collection in nearly every programming language is


the array, or ordered group of objects (ordered means you can access the elements
of a list using list[index]). In Dart, arrays are List objects, so most people just call
them lists.
Dart list literals look like JavaScript array literals. Here’s a simple Dart list:

var list = [1, 2, 3];

Note: Dart infers that list has type List<int>. If you try to add non-integer objects to


this list, the analyzer or runtime raises an error.

Dart 2.3 introduced the spread operator (...) and the null-aware spread


operator (...?), collection-if, and collection-for, which provide a concise way to
insert multiple elements into a collection.

Spread (…)

For example, you can use the spread operator (...) to insert all the elements of a list
into another list:

var list = [1, 2, 3];


var list2 = [0, ...list];
assert(list2.length == 4);

If the expression to the right of the spread operator might be null, you can avoid
exceptions by using a null-aware spread operator (...?):

var list;
var list2 = [0, ...?list];
assert(list2.length == 1);

collection-if/collection-for

you can now also use if/else  and for statements in your Collection literals.

void main() { 

 var name = 'Amit'; 

 var lst3 = [6,7];
 var lst2 = [3,4,5];
 var lst1 = [1,2, ...?lst2,
            if(name == 'Amit')
            ...lst3,
            for(int i = 8 ; i <= 10; i++)
            i  
            ];
 print(lst1);

Output : [1, 2, 3, 4, 5, 6, 7, 8, 9,10]

Sets

A set in Dart is an unordered collection of unique items. Because a set is unordered,


you can’t get a set’s items by index (position).
Here is a simple Dart set, created using a set literal:

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

Note: Dart infers that halogens has the type Set<String>. If you try to add the wrong
type of value to the set, the analyzer or runtime raises an error. 

To create an empty set, use {} preceded by a type argument, or assign {} to a


variable of type Set:

var names = <String>{};


// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.
Set or map? The syntax for map literals is similar to that for set literals. Because
map literals came first, {} defaults to the Map type. If you forget the type annotation
on {} or the variable it’s assigned to, then Dart creates an object of
type Map<dynamic, dynamic>.

Add items to an existing set using the add() or addAll() methods:


var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

To access elements from a Set use .elementsAt(index)


var myset = {2,1,4,3};
print( myset.elementAt(2));
Output: 4

Maps

In general, a map is an object that associates keys and values. Both keys and
values can be any type of object. Each key occurs only once, but you can use the
same value multiple times. 

Here are a couple of simple Dart maps, created using map literals:

var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};

var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};

Note: Dart infers that gifts has the type Map<String, String> and nobleGases has


the type Map<int, String>. If you try to add the wrong type of value to either map, the
analyzer or runtime raises an error.

You can create the same objects using a Map constructor:

var gifts = Map();


gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';

Add a new key-value pair to an existing map just as you would in JavaScript:

var gifts = {'first': 'partridge'};


gifts['fourth'] = 'calling birds'; // Add a key-value pair

Retrieve a value from a map the same way you would in JavaScript:

var gifts = {'first': 'partridge'};


assert(gifts['first'] == 'partridge');

If you look for a key that isn’t in a map, you get a null in return:

var gifts = {'first': 'partridge'};


assert(gifts['fifth'] == null);

To access elements from a Map use [key]:


var mymap = {11:'one',
             12:'two',
             13:'three'};
print(mymap[12]);   
Output: two (here 12 in mymap[12] is a key not an index.

Functions as first-class objects

You can pass a function as a parameter to another function. For example:

void printElement(int element) {


print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
Problem

Functions as first-class objects

void printElements(int x) {
print(x);
}
var mylist = <int>[1, 2, 3];
print(mylist.runtimeType);
mylist.forEach(printElements);
Output: List<int> 1 2 3
(works perfectly fine)

Problem occurs when i change var to List

List mylist = <int>[1, 2, 3];

print(mylist.runtimeType); //runtimeType is still the same List<int>


mylist.forEach(printElements); //now this statement is giving Error.

Error: The function 'printElements' has type 'void Function(int)' that isn't of expected
type 'void Function(dynamic)'. This means its parameter or return type doesn't
match what is expected

Solution
Dart has a static type system, so every variable has a static type, that is known by
the compiler.Every object also has a runtimeType, which is the actual type of this
object at runtime, and this may be a more specific type.

What you are doing here is basically this:

class Animal{}
class Cat extends Animal{
void meow(){}
}
void main(){
Animal animal = Cat();
print(animal.runtimeType); // prints Cat
animal.meow(); // fails, because the static type of animal is Animal, not cat
}

By writing

List mylist = <int>[1, 2, 3];

The static type of mylist is set to List<dynamic>.

Even if the type of the right-hand side would be inferred to List<int>, you specify the
type explicitly, which overwrites the type inference. Just List without generic type
parameter is shorthand for List<dynamic>, which is a more general type
than List<int>.

But your function

void printElements(int x) {
print(x);
}
can only take parameters of type int, not type dynamic! So because the static type of
your variable is List<dynamic>, the function passed to forEach must have a
signature of void Function(dynamic) but it has a signature of void Function(int).

You can fix this error either by specifying the correct type of the variable:
List<int> mylist = <int>[1, 2, 3];
or by letting the compiler figure out the correct type by itself:
var mylist = <int>[1, 2, 3];

Conditional expressions

Dart has two operators that let you concisely evaluate expressions that might
otherwise require if-else statements:
condition ? expr1 : expr2

If condition is true, evaluates expr1 (and returns its value); otherwise,


evaluates and returns the value of expr2.

expr1 ?? expr2
If expr1 is non-null, returns its value; otherwise, evaluates and returns the
value of expr2.

When you need to assign a value based on a boolean expression, consider using ?:.

var visibility = isPublic ? 'public' : 'private';


If the boolean expression tests for null, consider using ??.

String playerName(String name) => name ?? 'Guest';


The previous example could have been written at least two other ways, but not as
succinctly:

// Slightly longer version uses ?: operator.


String playerName(String name) => name != null ? name : 'Guest';

// Very long version uses if-else statement.


String playerName(String name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
Object-Orientated Language Features

Private Classes, Variables & Methods


Unlike Java, Dart doesn't have the keywords public, protected, and private to specify
the visibilities of fields or properties. If a class name, instance variable or method
starts with an underscore, it's private and cannot be accessed outside the Dart file in
which it is declared.

class ContactInfo {
String _name;
String _phone;
}

Constructors

Default Constructor
If you do not specify a constructor, a default constructor will be created for you
without arguments. If you do specify a constructor, the default constructor won’t be
created for you.
Constructor Syntax Shortcut
If you want to set the value of an instance variable in a constructor, you can use the
‘this.[instance variable name]’ to set it in the constructor signature.

void main()
{
Name myname = new Name('Amit', 'Verma');
myname.dispName();
print(myname.fName);
}

class Name
{
String fName, lName;
Name(this.fName, this.lName);

void dispName()
{
print('$fName $lName');
}
}

New Keyword

Dart doesn’t need you to use the ‘new’ keyword when invoking constructors.
However, you can keep it if you want.

Named Constructors
Dart allows named constructors and I have found them very useful indeed if you
want to instantiate the same class in different ways. Named constructors (if named
correctly) can also improve code readability & intent.

Example
A good example of a Flutter class that uses multiple named constructors is
EdgeInsets:
EdgeInsets.fromLTRB
EdgeInsets.all
EdgeInsets.only
EdgeInsets.symmetric
EdgeInsets.fromWindowPadding

Example

class ProcessingResult {
bool _error;
String _errMsg;

ProcessingResult.success() {
_error = false;
_errMsg = 'Hurray...!';
}
ProcessingResult.failure(this._errMsg) {
_error = true;
}

String joinMsg() {
return 'Error:' + _error.toString() + ' Message:' +
_errMsg;
}
}

void main() {
print(ProcessingResult.success().joinMsg());
print(ProcessingResult.failure('You are Fail').joinMsg());
}

another way

void main() {
ProcessingResult pass = ProcessingResult.success();
ProcessingResult fail = ProcessingResult.failure('you are fail');
print(pass.joinMsg());
print(fail.joinMsg());
}
Output
Error:false Message:Hurray...!
Error:true Message:you r fail
Imagine that the height field is expressed in feet and we want clients to supply the
height in meters. Dart also allows us to initialize fields with computations from static
methods (as they don't depend on an instance of the class):

class Robot {
static mToFt(m) => m * 3.281;
double height; // in ft
Robot(height) : this.height = mToFt(height);
}

Sometimes we must call super constructors when initializing:

class Machine {
String name;
Machine(this.name);
}

class Robot extends Machine {


static mToFt(m) => m * 3.281;
double height;
Robot(height, name) : this.height = mToFt(height), super(name);
}

Notice that super(...) must always be the last call in the initializer.

And if we needed to add more complex guards (than types) against a malformed
robot, we can use assert:

class Robot {
final double height;
Robot(height) : this.height = height, assert(height > 4.2);
}

In Dart, there is no private keyword. Instead, we use a convention: field names


starting with _ are private (library-private, actually).

class Robot {
double _height;
Robot(this._height);
}

Great! But now there is no way to access r.height. We can make


the height property read-only by adding a getter:

class Robot {
double _height;
Robot(this._height);

get height {
return this._height;
}
}
Getters are functions that take no arguments and conform to the uniform access
principle.
We can simplify our getter by using two shortcuts: single expression syntax (fat
arrow) and implicit this:

class Robot {
double _height;
Robot(this._height);

get height => _height;


}

Actually, we can think of public fields as private fields with getters and setters. That
is:

class Robot {
double height;
Robot(this.height);
}
is equivalent to:

class Robot {
double _height;
Robot(this._height);

get height => _height;


set height(value) => _height = value;
}

Keep in mind initializers only assign values to fields and it is therefore not possible to
use a setter in an initializer:

class Robot {
double _height;
Robot(this.height); // ERROR: 'height' isn't a field in the enclosing
class

get height => _height;


set height(value) => _height = value;
}

If a setter needs to be called, we’ll have to do that in a constructor body:

class Robot {
double _height;

Robot(h) {
height = h;
}

get height => _height;


set height(value) => _height = value;
}
We can do all sorts of things in constructor bodies, but we can’t return a value!

class Robot {
double height;
Robot(this.height) {
return this; // ERROR: Constructors can't return values
}
}

Getters and setters


Getters and setters are special methods that provide read and write access to an
object’s properties. Recall that each instance variable has an implicit getter, plus a
setter if appropriate. You can create additional properties by implementing getters
and setters, using the get and set keywords:
class Rectangle {
double left, top, width, height;

Rectangle(this.left, this.top, this.width, this.height);

// Define two calculated properties: right and bottom.


double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}

void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
With getters and setters, you can start with instance variables, later wrapping them
with methods, all without changing client code.

Final fields

Final fields are fields that can only be assigned once. Inside our class, we won’t be
able to use the setter for Final fields.

class Robot {
final double _height;
Robot(this._height);

get height => _height;


set height(value) => _height = value; // ERROR
}
The following won’t work because height, being final, must be initialized. And
initialization happens before the constructor body is run:

class Robot {
final double height;
Robot(double height) {
this.height = height; // ERROR: The final variable 'height' must be
initialized
}
}
Let’s fix it:

class Robot {
final double height;
Robot(this.height);
}

Default values
If most robots are 5-feet tall then we can avoid specifying the height each time. We
can make an argument optional and provide a default value:

class Robot {
final double height;
Robot([this.height = 5]);
}
So we can just call:
main() {
var r = Robot();
print(r.height); // 5

var r2d2 = Robot(3.576);


print(r2d2.height); // 3.576
}

Immutable robots
Our robots clearly have more attributes than a height. Let’s add some more!
class Robot {
final double height;
final double weight;
final String name;

Robot(this.height, this.weight, this.name);


}

main() {
final r = Robot(5, 170, "Walter");
r.name = "Steve"; // ERROR
}
As all fields are final, our robots are immutable! Once they are initialized, their
attributes can't be changed.
Now let’s imagine that robots respond to many different names:

class Robot {
final double height;
final double weight;
final List<String> names;
Robot(this.height, this.weight, this.names);
}
main() {
final r = Robot(5, 170, ["Walter"]);
print(r.names..add("Steve")); // [Walter, Steve]
}
Damn, using a List made our robot mutable again!

We can solve this with a const constructor:

class Robot {
final double height;
final double weight;
final List<String> names;

const Robot(this.height, this.weight, this.names);


}

main() {
final r = const Robot(5, 170, ["Walter"]);
print(r.names..add("Steve")); // ERROR: Unsupported operation: add
}
const can only be used with expressions that can be computed at compile time. Take
the following example:

import 'dart:math';

class Robot {
final double height;
final double weight;
final List<String> names;

const Robot(this.height, this.weight, this.names);


}

main() {
final r = const Robot(5, 170, ["Walter", Random().toString()]); //
ERROR: Invalid constant value
}

const instances are canonicalized which means that equal instances point to the
same object in memory space when running.
And yes, using const constructors can improve performance in Flutter applications.

Constant constructors
If your class produces objects that never change, you can make these objects
compile-time constants. To do this, define a const constructor and make sure that
all instance variables are final.
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final double x, y;

const ImmutablePoint(this.x, this.y);


}
Constant constructors don’t always create constants

Naming things
Having to construct a robot like Robot(5, ["Walter"]) is not very explicit.
Dart has named arguments! Naturally, they can be provided in any order and are all
optional by default:

class Robot {
final double height;
final double weight;
final List<String> names;

Robot({ this.height, this.weight, this.names });


}

main() {
final r = Robot(height: 5, names: ["Walter"]);
print(r.height); // 5
}
But we can annotate a field with @required:

class Robot {
final double height;
final double weight;
final List<String> names;

Robot({ this.height, @required this.weight, this.names });


}

How about making the attributes private?


class Robot {
final double _height;
final double _weight;
final List<String> _names;

Robot({ this._height, this._weight, this._names }); // ERROR: Named


optional parameters can't start with an underscore
}
It fails! Unlike with positional arguments, we need to specify the mappings in the
initializer:

class Robot {
final double _height;
final double _weight;
final List<String> _names;

Robot({ height, weight, names }) : _height = height, _weight = weight,


_names = names;
get height => _height;
get weight => _weight;
get names => _names;
}

main() {
print(Robot(height: 5).height); // 5
}

Need default values?

class Robot {
final double _height;
final double _weight;
final List<String> _names;

Robot({ height, weight, names }) : _height = height ?? 7, _weight =


weight, _names = names;

get height => _height;


get weight => _weight;
get names => _names;
}

main() {
print(Robot().height); // 7
}
We simply employ the handy “if-null” operator ??.
Or, for example, a static function that returns default values:

class Robot {
final double _height;
final double _weight;
final List<String> _names;

static _d(key) => { 'height': 5, 'weight': 100, 'names': <String>[] }


[key];

Robot({ height, weight, names }) :


_height = height ?? _d('height'),
_weight = weight ?? _d('weight'),
_names = names ?? _d('names');

@override
toString() => 'height: $_height / weight: $_weight / names: $_names';
}

main() {
print(Robot(height: 7)); // height: 7 / weight: 100 / names: []
}

Named constructors
Not only can arguments be named. We can give names to any number of
constructors:
class Robot {
final double height;
Robot(this.height);

Robot.fromPlanet(String planet) : height = (planet == 'geonosis') ?


2 : 7;
Robot.copy(Robot other) : this(other.height);
}

main() {
print(Robot.copy(Robot(7)).height); // 7
print(new Robot.fromPlanet('geonosis').height); // 2
print(new Robot.fromPlanet('earth').height); // 7
}
What happened in copy? We used this to call the default constructor, effectively
"redirecting" the instantiation.
( new is optional but I sometimes like to use it, since it clearly states the intent.)

Invoking named super constructors works as expected:

class Machine {
String name;
Machine();
Machine.named(this.name);
}

class Robot extends Machine {


final double height;
Robot(this.height);

Robot.named({ height, name }) : this.height = height,


super.named(name);
}

main() {
print(Robot.named(height: 7, name: "Walter").name); // Walter
}
Note that named constructors require an unnamed constructor to be defined!
Keeping it private
But what if we didn’t want to expose a public constructor? Only named?
We can make a constructor private by prefixing it with an underscore:

class Robot {
Robot._();
}
Applying this knowledge to our previous example:

class Machine {
String name;
Machine._();
Machine.named(this.name);
}
class Robot extends Machine {
final double height;
Robot._(this.height, name) : super.named(name);

Robot.named({ height, name }) : this._(height, name);


}

main() {
print(Robot.named(height: 7, name: "Walter").name); // Walter
}
The named constructor is “redirecting” to the private default constructor (which in
turn delegates part of the creation to its Machine ancestor).
Consumers of this API only see Robot.named() as a way to get robot instances.

A robot factory
We said constructors were not allowed to return. Guess what?
Factory constructors can!

class Robot {
final double height;

Robot._(this.height);

factory Robot() {
return Robot._(7);
}
}

main() {
print(Robot().height); // 7
}
Factory constructors are syntactic sugar for the “factory pattern”, usually
implemented with static functions.
They appear like a constructor from the outside (useful for example to avoid breaking
API contracts), but internally they can delegate instance creation invoking a “normal”
constructor. This explains why factory constructors do not have initializers.
Since factory constructors can return other instances (so long as they satisfy the
interface of the current class), we can do very useful things like:
 caching: conditionally returning existing objects (they might be expensive to
create)
 subclasses: returning other instances such as subclasses
They work with both normal and named constructors!
Here’s our robot warehouse, that only supplies one robot per height:

class Robot {
final double height;

static final _cache = <double, Robot>{};

Robot._(this.height);

factory Robot(height) {
return _cache[height] ??= Robot._(height);
}
}

main() {
final r1 = Robot(7);
final r2 = Robot(7);
final r3 = Robot(9);

print(r1.height); // 7
print(r2.height); // 7
print(identical(r1, r2)); // true
print(r3.height); // 9
print(identical(r2, r3)); // false
}
Finally, to demonstrate how a factory would instantiate subclasses, let’s create
different robot brands that calculate prices as a function of height:
abstract class Robot {
factory Robot(String brand) {
if (brand == 'fanuc') return Fanuc(2);
if (brand == 'yaskawa') return Yaskawa(9);
if (brand == 'abb') return ABB(7);
throw "no brand found";
}
double get price;
}

class Fanuc implements Robot {


final double height;
Fanuc(this.height);
double get price => height * 2922.21;
}

class Yaskawa implements Robot {


final double height;
Yaskawa(this.height);
double get price => height * 1315 + 8992;
}

class ABB implements Robot {


final double height;
ABB(this.height);
double get price => height * 2900 - 7000;
}

main() {
try {
print(Robot('fanuc').price); // 5844.42
print(Robot('abb').price); // 13300
print(Robot('flutter').price);
} catch (err) {
print(err); // no brand found
}
}
Singletons
Singletons are classes that only ever create one instance. We think of this as a specific
case of caching!
Let’s implement the singleton pattern in Dart:
class Robot {
static final Robot _instance = new Robot._(7);
final double height;

factory Robot() {
return _instance;
}

Robot._(this.height);
}

main() {
var r1 = Robot();
var r2 = Robot();
print(identical(r1, r2)); // true
print(r1 == r2); // true
}
The factory constructor Robot(height) simply always returns the one and only
instance that was created when loading the Robot class. (So in this case, I prefer not
to use new before Robot.)

Factory constructors
Use the factory keyword when implementing a constructor that doesn’t always
create a new instance of its class. For example, a factory constructor might return an
instance from a cache, or it might return an instance of a subtype.

The following example demonstrates a factory constructor returning objects from a


cache:
class Logger {
final String name;
bool mute = false;

// _cache is library-private, thanks to


// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};

factory Logger(String name) {


return _cache.putIfAbsent(
name, () => Logger._internal(name));
}

Logger._internal(this.name);

void log(String msg) {


if (!mute) print(msg);
}
}
Note: Factory constructors have no access to this.
Invoke a factory constructor just like you would any other constructor :
var logger = Logger('UI');
logger.log('Button clicked');

Abstract methods

Instance, getter, and setter methods can be abstract, defining an interface but
leaving its implementation up to other classes. Abstract methods can only exist
in abstract classes.
To make a method abstract, use a semicolon (;) instead of a method body:
abstract class Doer {
// Define instance variables and methods...

void doSomething(); // Define an abstract method.


}

class EffectiveDoer extends Doer {


void doSomething() {
// Provide an implementation, so the method is not abstract here...
}
}

Abstract classes

Use the abstract modifier to define an abstract class—a class that can’t be


instantiated. Abstract classes are useful for defining interfaces, often with some
implementation. If you want your abstract class to appear to be instantiable, define
a factory constructor.
Abstract classes often have abstract methods. Here’s an example of declaring an
abstract class that has an abstract method:

// This class is declared abstract and thus


// can't be instantiated.
abstract class AbstractContainer {
// Define constructors, fields, methods...

void updateChildren(); // Abstract method.


}

Implicit interfaces

Every class implicitly defines an interface containing all the instance members of the
class and of any interfaces it implements. If you want to create a class A that
supports class B’s API without inheriting B’s implementation, class A should
implement the B interface.
A class implements one or more interfaces by declaring them in
an implements clause and then providing the APIs required by the interfaces. For
example:
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;

// Not in the interface, since this is a constructor.


Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}

// An implementation of the Person interface.


class Impostor implements Person {
get _name => '';

String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
Here’s an example of specifying that a class implements multiple interfaces:
class Point implements Comparable, Location {...}

Extending a class

Use extends to create a subclass, and super to refer to the superclass:


class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}

class SmartTelevision extends Television {


void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}

Overriding members

Subclasses can override instance methods, getters, and setters. You can use
the @override annotation to indicate that you are intentionally overriding a
member:
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}
To narrow the type of a method parameter or instance variable in code that is type
safe, you can use the covariant keyword.

The covariant keyword


Some (rarely used) coding patterns rely on tightening a type by overriding a
parameter’s type with a subtype, which is invalid. In this case, you can use
the covariant keyword to tell the analyzer that you are doing this intentionally. This
removes the static error and instead checks for an invalid argument type at runtime.
Version note: The covariant keyword was introduced in 1.22. It replaces
the @checked annotation.
The following shows how you might use covariant:
class Animal {
void chase(Animal x) { ... }
}

class Mouse extends Animal { ... }

class Cat extends Animal {


void chase(covariant Mouse x) { ... }
}
Although this example shows using covariant in the subtype, the covariant keyword
can be placed in either the superclass or the subclass method. Usually the superclass
method is the best place to put it. The covariant keyword applies to a single
parameter and is also supported on setters and fields.

Operator overloading
Here’s an example of a class that overrides the + and - operators:
class Vector {
final int x, y;

Vector(this.x, this.y);

Vector operator +(Vector v) => Vector(x + v.x, y + v.y);


Vector operator -(Vector v) => Vector(x - v.x, y - v.y);

// Operator == and hashCode not shown. For details, see note below.
// ···
}

void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);

assert(v + w == Vector(4, 5));


assert(v - w == Vector(0, 1));
}

Extension methods

Extension methods, introduced in Dart 2.7, are a way to add functionality to existing
libraries. You might use extension methods without even knowing it. For example,
when you use code completion in an IDE, it suggests extension methods alongside
regular methods.
Here’s an example of using an extension method on String named parseInt() that’s
defined in string_apis.dart:
import 'string_apis.dart';
...
print('42'.padLeft(5)); // Use a String method.
print('42'.parseInt()); // Use an extension method.
Overview (Extension methods)
When you’re using someone else’s API or when you implement a library that’s
widely used, it’s often impractical or impossible to change the API. But you might
still want to add some functionality.
For example, consider the following code that parses a string into an integer:

int.parse('42')

It might be nice — shorter and easier to use with tools — to have that functionality
be on String instead:

'42'.parseInt()

To enable that code, you can import a library that contains an extension of
the String class:

import 'string_apis.dart';
// ···
print('42'.parseInt()); // Use an extension method.

Extensions can define not just methods, but also other members such as getter,
setters, and operators. Also, extensions have names, which can be helpful if an API
conflict arises. Here’s how you might implement the extension method parseInt(),
using an extension (named NumberParsing) that operates on strings:

extension NumberParsing on String {


int parseInt() {
return int.parse(this);
}
// ···
}

You can’t invoke extension methods on variables of type dynamic. For example, the
following code results in a runtime exception:

dynamic d = '2';
print(d.parseInt()); // Runtime exception: NoSuchMethodError

Extension methods do work with Dart’s type inference. The following code is fine
because the variable v is inferred to have type String:

var v = '2';
print(v.parseInt()); // Output: 2

The reason that dynamic doesn’t work is that extension methods are resolved


against the static type of the receiver. Because extension methods are resolved
statically, they’re as fast as calling a static function.

Implementing extension methods

Use the following syntax to create an extension:


extension <extension name> on <type> {
(<member definition>)*
}

For example, here’s how you might implement an extension on the String class:

extension NumberParsing on String {


int parseInt() {
return int.parse(this);
}

double parseDouble() {
return double.parse(this);
}
}

To create a local extension that’s visible only in the library where it’s declared, either
omit the extension name or give it a name that starts with an underscore (_).
The members of the extension can be methods, getters, setters, operators.
Extensions can also have static fields and static helper methods.

Implementing generic extensions


Extensions can have generic type parameters. For example, here’s some code that
extends the built-in List<T> type with a getter, an operator, and a method:

extension MyFancyList<T> on List<T> {


int get doubleLength => length * 2;
List<T> operator -() => reversed.toList();
List<List<T>> split(int at) => <List<T>>[sublist(0, at), sublist(at)];
}

The type T is bound based on the static type of the list that the methods are called
on.

Enumerated types

Enumerated types, often called enumerations or enums, are a special kind of class


used to represent a fixed number of constant values.

Using enums
Declare an enumerated type using the enum keyword:

enum Color { red, green, blue }

Each value in an enum has an index getter, which returns the zero-based position of
the value in the enum declaration. For example, the first value has index 0, and the
second value has index 1.

assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);

To get a list of all of the values in the enum, use the enum’s values constant.
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);

You can use enums in switch statements, and you’ll get a warning if you don’t handle
all of the enum’s values:

var aColor = Color.blue;

switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // Without this, you see a WARNING.
print(aColor); // 'Color.blue'
}

Enumerated types have the following limits:

 You can’t subclass, mix in, or implement an enum.


 You can’t explicitly instantiate an enum.

Mixin

We have here a superclass called Animal which has three subclasses


(Mammal, Bird, and Fish). At the bottom, we have concrete classes.
The little squares represent behavior. For example, the blue square indicates that an
instance of a class with this behavior can swim.

Some animals share common behavior: A cat and a dove can both walk, but the cat
cannot fly.
These kinds of behavior are orthogonal to this classification, so we cannot implement
these behavior in the superclasses.

If a class could have more than one superclass, it would be easy, we could create
three other classes: Walker, Swimmer, Flyer. After that, we would just have to
inherit Dove and Cat from the Walker class. But in Dart, every class (except
for Object) has exactly one superclass.

Instead of inheriting from the Walker class, we could implement it, as it if was an


interface, but we should have to implement the behavior in multiple classes, so it’s
not a good solution.

We need a way of reusing a class’s code in multiple class hierarchies.


You know what? Mixins are exactly that:

Mixins are a way of reusing a class’s code in multiple class hierarchies.

We saw how mixins can be useful, let’s see how to create and use them.
Mixins are implicitly defined via ordinary class declarations:

class Walker {
void walk() {
print("I'm walking");
}
}
If we want to prevent our mixin to be instantiated or extended, we can define it like
that:

abstract class Walker {


// This class is intended to be used as a mixin, and should not be
// extended directly.
factory Walker._() => null;

void walk() {
print("I'm walking");
}
}
To use a mixin, use the with keyword followed by one or more mixin name:
class Cat extends Mammal with Walker {}

class Dove extends Bird with Walker, Flyer {}

Defining the Walker mixin on the Cat class, allows us to call the walk method but


not the fly method (defined in Flyer).
main() {
Cat cat = Cat();
Dove dove = Dove();

// A cat can walk.


cat.walk();

// A dove can walk and fly.


dove.walk();
dove.fly();
// A normal cat cannot fly.
// cat.fly(); // Uncommenting this does not compile.
}

Details

class A {
String getMessage() => 'A';
}

class B {
String getMessage() => 'B';
}

class P {
String getMessage() => 'P';
}

class AB extends P with A, B {}

class BA extends P with B, A {}

void main() {
String result = '';

AB ab = AB();
result += ab.getMessage();

BA ba = BA();
result += ba.getMessage();

print(result);
}

Both, AB and BA classes extend the P class with A and B mixins but in a different


order. All three A, B and P classes have a method called getMessage.

First, we call the getMessage method of the AB class, then


the getMessage method of the BA class.

So, what do you think the resulting output will be?


I’m giving you five propositions:

A. It does not compile


B. BA
C. AB
D. BAAB
E. ABBA

The answer is the proposition B! The program prints BA.


I think you guessed that the order in which the mixins are declared is very important.
Why? How is it working?

Linearization
When you apply a mixin to a class, keep in mind this:

Mixins in Dart work by creating a new class that layers the implementation of the
mixin on top of a superclass to create a new class — it is not “on the side” but “on
top” of the superclass, so there is no ambiguity in how to resolve lookups.
In fact, the code
class AB extends P with A, B {}

class BA extends P with B, A {}

is semantically equivalent to
class PA = P with A;
class PAB = PA with B;

class AB extends PAB {}

class PB = P with B;
class PBA = PB with A;

class BA extends PBA {}

The final inheritance diagram can be represented like this:


New classes are created between AB and P. These new classes are a mix-in between
the superclass P and the classes A and B.

As you can see, there is no multiple inheritance in there!

Mixins is not a way to get multiple inheritance in the classical sense. Mixins is a
way to abstract and reuse a family of operations and state. It is similar to the reuse
you get from extending a class, but it is compatible with single-inheritance because
it is linear.

One important thing to remember is that the order in which mixins are declared
represents the inheritance chain, from the top superclass to the bottom one.

Types

What is the type of a mixin application instance? In general, it is a subtype of its


superclass, and also a subtype of the type denoted by the mixin name itself, that is,
the type of the original class.

So it means that this program


class A {
String getMessage() => 'A';
}

class B {
String getMessage() => 'B';
}

class P {
String getMessage() => 'P';
}

class AB extends P with A, B {}

class BA extends P with B, A {}

void main() {
AB ab = AB();
print(ab is P);
print(ab is A);
print(ab is B);

BA ba = BA();
print(ba is P);
print(ba is A);
print(ba is B);
}
will print six lines with true in the console.

Detailed explanation
Since each mixin application creates a new class, it also creates a
new interface (because all Dart classes also define interfaces). As described, the
new class extends the superclass and includes copies of the mixin class members,
but it also implements the mixin class interface.
In most cases, there is no way to refer to that mixin-application class or its
interface; the class for Super with Mixin is just an anonymous superclass of the
class declared like class C extends Super with Mixin {}. If you name a mixin
application like class CSuper = Super with Mixin {}, then you can refer to the mixin
application class and its interface, and it will be a sub-type of
both Super and Mixin.

When to use mixins?

Mixins are very helpful when we want to share a behavior across multiple classes that
don’t share the same class hierarchy, or when it doesn’t make sense to implement
such a behavior in a superclass.

It’s typically the case for serialization (Take a look at jaguar_serializer for example)
or persistence. But you can also use mixins to provide some utility functions (like
the RenderSliverHelpers in Flutter).

Take a time to play with this feature, and I’m sure you’ll find new use cases . Don’t
restrict yourself to stateless mixins, you can absolutely store variables and use them!

Mixins specification is evolving

To give you a glimpse into the future, consider this source code:
abstract class Super {
void method() {
print("Super");
}
}

class MySuper implements Super {


void method() {
print("MySuper");
}
}

mixin Mixin on Super {


void method() {
super.method();
print("Sub");
}
}

class Client extends MySuper with Mixin {}

void main() {
Client().method();
}
The mixin declaration from line 13 to 18, indicates a superclass constraint
on Super. It means that in order to apply this mixin to a class, this class must extend
or implementSuper because the mixin uses a feature provided by Super.

The output of this program would be:


MySuper
Sub

If you wonder why, keep in mind how mixins are linearized:

In fact, the call to super.method() on line 15 actually calls the method declared


on line 8.

Complete Animal example


abstract class Animal {}

abstract class Mammal extends Animal {}

abstract class Bird extends Animal {}

abstract class Fish extends Animal {}

abstract class Walker {


// This class is intended to be used as a mixin, and should not be
// extended directly.
factory Walker._() => null;

void walk() {
print("I'm walking");
}
}

abstract class Swimmer {


// This class is intended to be used as a mixin, and should not be
// extended directly.
factory Swimmer._() => null;

void swim() {
print("I'm swimming");
}
}

abstract class Flyer {


// This class is intended to be used as a mixin, and should not be
// extended directly.
factory Flyer._() => null;

void fly() {
print("I'm flying");
}
}

class Dolphin extends Mammal with Swimmer {}

class Bat extends Mammal with Walker, Flyer {}

class Cat extends Mammal with Walker {}

class Dove extends Bird with Walker, Flyer {}

class Duck extends Bird with Walker, Swimmer, Flyer {}

class Shark extends Fish with Swimmer {}

class FlyingFish extends Fish with Swimmer, Flyer {}


From Dart documentation

Adding features to a class: mixins


Mixins are a way of reusing a class’s code in multiple class hierarchies.
To use a mixin, use the with keyword followed by one or more mixin names. The
following example shows two classes that use mixins:

class Musician extends Performer with Musical {


// ···
}

class Maestro extends Person


with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}

To implement a mixin, create a class that extends Object and declares no


constructors. Unless you want your mixin to be usable as a regular class, use
the mixin keyword instead of class. For example:

mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;

void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}

To specify that only certain types can use the mixin — for example, so your mixin
can invoke a method that it doesn’t define — use on to specify the required
superclass:

mixin MusicalPerformer on Musician {


// ···
}
Class variables and methods
Use the static keyword to implement class-wide variables and methods.

Static variables
Static variables (class variables) are useful for class-wide state and constants:

class Queue {
static const initialCapacity = 16;
// ···
}

void main() {
assert(Queue.initialCapacity == 16);
}
Static variables aren’t initialized until they’re used.

Static methods
Static methods (class methods) do not operate on an instance, and thus do not have
access to this. For example:

import 'dart:math';

class Point {
double x, y;
Point(this.x, this.y);

static double distanceBetween(Point a, Point b) {


var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}

void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}

Note: Consider using top-level functions, instead of static methods, for common or


widely used utilities and functionality.
You can use static methods as compile-time constants. For example, you can pass a
static method as a parameter to a constant constructor.
Generics

What are Generics, and why should we use them?

Generic programming is a style of computer programming in


which algorithms are written in terms of types to-be-specified-later that are
then instantiated when needed for specific types provided as parameters.

If you look at the API documentation for the basic array type, List, you’ll see that the
type is actually List<E>. The <…> notation marks List as
a generic (or parameterized) type—a type that has formal type parameters. By
convention, most type variables have single-letter names, such as E, T, S, K, and V.

DO follow existing mnemonic conventions when naming type parameters.

Single letter names aren’t exactly illuminating, but almost all generic types use them.
Fortunately, they mostly use them in a consistent, mnemonic way. The conventions
are:

E for the element type in a collection:

class IterableBase<E> {}
class List<E> {}
class HashSet<E> {}
class RedBlackTree<E> {}

K and V for the key and value types in an associative collection:

class Map<K, V> {}


class Multimap<K, V> {}
class MapEntry<K, V> {}

R for a type used as the return type of a function or a class’s methods. This isn’t


common, but appears in typedefs sometimes and in classes that implement the
visitor pattern:

abstract class ExpressionVisitor<R> {


R visitBinary(BinaryExpression node);
R visitLiteral(LiteralExpression node);
R visitUnary(UnaryExpression node);
}

Otherwise, use T, S, and U for generics that have a single type parameter and where
the surrounding type makes its meaning obvious. There are multiple letters here to
allow nesting without shadowing a surrounding name. For example:

class Future<T> {
Future<S> then<S>(FutureOr<S> onValue(T value)) => ...
}
Here, the generic method then<S>() uses S to avoid shadowing the T on Future<T>.
If none of the above cases are a good fit, then either another single-letter mnemonic
name or a descriptive name is fine:

class Graph<N, E> {


final List<N> nodes = [];
final List<E> edges = [];
}

class Graph<Node, Edge> {


final List<Node> nodes = [];
final List<Edge> edges = [];
}

In practice, the existing conventions cover most type parameters.

Why use generics?

Generics are often required for type safety, but they have more benefits than just
allowing your code to run:
 Properly specifying generic types results in better generated code.
 You can use generics to reduce code duplication.
 Stronger type checks at compile time.
 Fixing compile-time errors is easier than fixing runtime errors
 Elimination of casts. Which in turn is quicker.
 Enabling coders to implement generic solutions, which can be reused for
multiple purposes.
 Future proofed for the datatypes of tomorrow.

If you intend for a list to contain only strings, you can declare it
as List<String> (read that as “list of string”). That way you, your fellow
programmers, and your tools can detect that assigning a non-string to the list is
probably a mistake. Here’s an example:

var names = List<String>();


names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error
Another reason for using generics is to reduce code duplication. Generics let you
share a single interface and implementation between many types, while still taking
advantage of static analysis. For example, say you create an interface for caching an
object:

abstract class ObjectCache {


Object getByKey(String key);
void setByKey(String key, Object value);
}
You discover that you want a string-specific version of this interface, so you create
another interface:
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}

Later, you decide you want a number-specific version of this interface… You get the
idea.
Generic types can save you the trouble of creating all these interfaces. Instead, you
can create a single interface that takes a type parameter:

abstract class Cache<T> {


T getByKey(String key);
void setByKey(String key, T value);
}
In this code, T is the stand-in type. It’s a placeholder that you can think of as a type
that a developer will define later

Using collection literals

List, set, and map literals can be parameterized. Parameterized literals are just like
the literals you’ve already seen, except that you add <type> (for lists and sets)
or <keyType, valueType> (for maps) before the opening bracket. Here is an example
of using typed literals:
var names = <String>['Seth', 'Kathy', 'Lars'];
var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};

Using parameterized types with constructors

To specify one or more types when using a constructor, put the types in angle
brackets (<...>) just after the class name. For example:
var nameSet = Set<String>.from(names);

The following code creates a map that has integer keys and values of type View :
var views = Map<int, View>();

Generic collections and the types they contain

Dart generic types are reified, which means that they carry their type information
around at runtime. For example, you can test the type of a collection:

var names = List<String>();


names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
Note: In contrast, generics in Java use erasure, which means that generic type
parameters are removed at runtime. In Java, you can test whether an object is a List,
but you can’t test whether it’s a List<String>.

Restricting the parameterized type

When implementing a generic type, you might want to limit the types of its
parameters. You can do this using extends.

class Foo<T extends SomeBaseClass> {


// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}


It’s OK to use SomeBaseClass or any of its subclasses as generic argument:

var someBaseClassFoo = Foo<SomeBaseClass>();


var extenderFoo = Foo<Extender>();
It’s also OK to specify no generic argument:

var foo = Foo();


print(foo); // Instance of 'Foo<SomeBaseClass>'
Specifying any non-SomeBaseClass type results in an error:

var foo = Foo<Object>();

Using generic methods

Initially, Dart’s generic support was limited to classes. A newer syntax,


called generic methods, allows type arguments on methods and functions:

T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}
Here the generic type parameter on first (<T>) allows you to use the type
argument T in several places:

 In the function’s return type (T).


 In the type of an argument (List<T>).
 In the type of a local variable (T tmp).
Asynchronous programming

Dart asynchronous programming: Isolates and event loops

Dart, despite being a single-threaded language, offers support for futures, streams,
background work, and all the other things you need to write in a modern,
asynchronous, and (in the case of Flutter) reactive way.

Isolates

An isolate is what all Dart code runs in. It’s like a little space on the machine with its
own, private chunk of memory and a single thread running an event loop.

An isolate has its own memory and a single thread of execution that runs an event loop.

In a lot of other languages like C++, you can have multiple threads sharing the same
memory and running whatever code you want. In Dart, though, each thread is in its
own isolate with its own memory, and the thread just processes events (more on that
in a minute).

Many Dart apps run all their code in a single isolate, but you can have more than one
if you need it. If you have a computation to perform that’s so enormous it could cause
you to drop frames if it were run in the main isolate, then you can
use Isolate.spawn() or Flutter’s compute() function. Both of those functions create a
separate isolate to do the number crunching, leaving your main isolate free to — say
— rebuild and render the widget tree.

Two isolates, each with its own memory and thread of execution.

The new isolate gets its own event loop and its own memory, which the original
isolate — even though it’s the parent of this new one — isn’t allowed to access. That’s
the source of the name isolate: these little spaces are kept isolated from one another.
In fact, the only way that isolates can work together is by passing messages back and
forth. One isolate sends a message to the other, and the receiving isolate processes
that message using its event loop.

This lack of shared memory might sound kind of strict, especially if you’re coming
from a language like Java or C++, but it has some key benefits for Dart coders.

For example, memory allocation and garbage collection in an isolate don’t require
locking. There’s only one thread, so if it’s not busy, you know the memory isn’t being
mutated. That works out well for Flutter apps, which sometimes need to build up and
tear down a bunch of widgets quickly.

Event loops

Now that you’ve had a basic introduction to isolates, let’s dig in to what really makes
asynchronous code possible: the event loop.

Imagine the life of an app stretched out on a timeline. The app starts, the app stops,
and in between a bunch of events occur — I/O from the disk, finger taps from the
user… all kinds of stuff.

Your app can’t predict when these events will happen or in what order, and it has to
handle all of them with a single thread that never blocks. So, the app runs an event
loop. It grabs the oldest event from its event queue, processes it, goes back for the
next one, processes it, and so on, until the event queue is empty.

The whole time the app is running — you’re tapping on the screen, things are
downloading, a timer goes off — that event loop is just going around and around,
processing those events one at a time.

The event loop processes one event at a time.

When there’s a break in the action, the thread just hangs out, waiting for the next
event. It can trigger the garbage collector, get some coffee, whatever.
All of the high-level APIs and language features that Dart has for asynchronous
programming — futures, streams, async and await — they’re all built on and
around this simple loop.

For example, say you have a button that initiates a network request, like this one:
RaisedButton(
child: Text('Click me'),
onPressed: () {
final myFuture = http.get('https://example.com');
myFuture.then((response) {
if (response.statusCode == 200) {
print('Success!');
}
});
},
)

When you run your app, Flutter builds the button and puts it on screen. Then your
app waits.

Your app’s event loop just sort of idles, waiting for the next event. Events that
aren’t related to the button might come in and get handled, while the button sits
there waiting for the user to tap on it. Eventually they do, and a tap event enters
the queue.

That event gets picked up for processing. Flutter looks at it, and the rendering
system says, “Those coordinates match the raised button,” so Flutter executes the
onPressed function. That code initiates a network request (which returns a future)
and registers a completion handler for the future by using the then() method.
That’s it. The loop is finished processing that tap event, and it’s discarded.

Now, onPressed is a property of RaisedButton, and the network event uses a


callback for a future, but both of those techniques are doing the same basic thing.
They’re both a way to tell Flutter, “Hey, later on, you might see a particular type of
event come in. When you do, please execute this piece of code.”

So, onPressed is waiting for a tap, and the future is waiting for network data, but
from Dart’s perspective, those are both just events in the queue.

And that’s how asynchronous coding works in Dart. Futures, streams, async and
await — these APIs are all just ways for you to tell Dart’s event loop, “Here’s some
code, please run it later.”

If we look back at the code example, you can now see exactly how it’s broken up
into blocks for particular events. There’s the initial build (1), the tap event (2), and
the network response event (3).
RaisedButton( // (1)
child: Text('Click me'),
onPressed: () { // (2)
final myFuture = http.get('https://example.com');
myFuture.then((response) { // (3)
if (response.statusCode == 200) {
print('Success!');
}
});
},
)

Asynchronous programming: futures, async, await

Example: Incorrectly using an asynchronous function

The following example shows the wrong way to use an asynchronous function
(fetchUserOrder()). Later you’ll fix the example using async and await. Before
running this example, try to spot the issue – what do you think the output will be?
// This example shows how *not* to write asynchronous Dart code.

String createOrderMessage() {
var order = fetchUserOrder();
return 'Your order is: $order';
}

Future<String> fetchUserOrder() =>


// Imagine that this function is more complex and slow.
Future.delayed(
Duration(seconds: 2),
() => 'Large Latte',
);

void main() {
print(createOrderMessage());
}

Output: Your order is: Instance of '_Future<String>'

Here’s why the example fails to print the value that fetchUserOrder() eventually


produces:

 fetchUserOrder() is an asynchronous function that, after a delay, provides a


string that describes the user’s order: a “Large Latte”.
 To get the user’s order, createOrderMessage() should
call fetchUserOrder() and wait for it to finish.
Because createOrderMessage() does not wait for fetchUserOrder() to
finish, createOrderMessage() fails to get the string value
that fetchUserOrder() eventually provides.
 Instead, createOrderMessage() gets a representation of pending work to be
done: an uncompleted future. You’ll learn more about futures in the next
section.
 Because createOrderMessage() fails to get the value describing the user’s
order, the example fails to print “Large Latte” to the console, and instead
prints “Your order is: Instance of ‘_Future'".
In the next sections you’ll learn about futures and about working with futures (using async and await) so that you’ll be able
to write the code necessary to make fetchUserOrder() print the desired value (“Large Latte”) to the console.

Key terms:

 synchronous operation: A synchronous operation blocks other operations from executing until it completes.
 synchronous function: A synchronous function only performs synchronous operations.
 asynchronous operation: Once initiated, an asynchronous operation allows other operations to execute before it
completes.
 asynchronous function: An asynchronous function performs at least one asynchronous operation and can also
perform synchronous operations.

What is a future?

A future (lower case “f”) is an instance of the Future (capitalized “F”) class. A future


represents the result of an asynchronous operation, and can have two states:
uncompleted or completed.

Uncompleted
When you call an asynchronous function, it returns an uncompleted future. That
future is waiting for the function’s asynchronous operation to finish or to throw an
error.

Completed
If the asynchronous operation succeeds, the future completes with a value.
Otherwise it completes with an error.

Completing with a value


A future of type Future<T> completes with a value of type T. For example, a future
with type Future<String> produces a string value. If a future doesn’t produce a
usable value, then the future’s type is Future<void>.

Completing with an error


If the asynchronous operation performed by the function fails for any reason, the
future completes with an error.

Example: Introducing futures

In the following example, fetchUserOrder() returns a future that completes after


printing to the console. Because it doesn’t return a usable
value, fetchUserOrder() has the type Future<void>. Before you run the example, try
to predict which will print first: “Large Latte” or “Fetching user order…”.
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info from another
service or database.
return Future.delayed(Duration(seconds: 2), () => print('Large
Latte'));
}
void main() {
fetchUserOrder();
print('Fetching user order...');
}

Output: Fetching user order... Large Latte

In the preceding example, even though fetchUserOrder() executes before


the print() call on line 8, the console shows the output from line 8 (“Fetching user
order…”) before the output from fetchUserOrder() (“Large Latte”). This is
because fetchUserOrder() delays before it prints “Large Latte”.

Example: Completing with an error

Run the following example to see how a future completes with an error. A bit later
you’ll learn how to handle the error.
Future<void> fetchUserOrder() {
// Imagine that this function is fetching user info but encounters a bug
return Future.delayed(Duration(seconds: 2),
() => throw Exception('Logout failed: user ID is invalid'));
}

void main() {
fetchUserOrder();
print('Fetching user order...');
}

Output: Fetching user order... Uncaught Error: Exception: Logout failed: user ID is
invalid

In this example, fetchUserOrder() completes with an error indicating that the user


ID is invalid.
Quick review:

 A Future<T> instance produces a value of type T.


 If a future doesn’t produce a usable value, then the future’s type is Future<void>.
 A future can be in one of two states: uncompleted or completed.
 When you call a function that returns a future, the function queues up work to be done and returns an uncompleted
future.
 When a future’s operation finishes, the future completes with a value or with an error.

Key terms:

 Future: the Dart Future class.


 future: an instance of the Dart Future class.

Working with futures: async and await


The async and await keywords provide a declarative way to define asynchronous
functions and use their results. Remember these two basic guidelines when
using async and await:

 To define an async function, add async before the function body:


 The await keyword works only in async functions.

Here’s an example that converts main() from a synchronous to asynchronous


function.

First, add the async keyword before the function body:

void main() async { ··· }

If the function has a declared return type, then update the type to be Future<T>,
where T is the type of the value that the function returns. If the function doesn’t
explicitly return a value, then the return type is Future<void>:

Future<void> main() async { ··· }

Now that you have an async function, you can use the await keyword to wait for a
future to complete:

print(await createOrderMessage());

As the following two examples show, the async and await keywords result in


asynchronous code that looks a lot like synchronous code. The only differences are
highlighted in the asynchronous example, which — if your window is wide enough —
is to the right of the synchronous example.
The asynchronous example is different in three ways:

 The return type for createOrderMessage() changes


from String to Future<String>.
 The async keyword appears before the function bodies
for createOrderMessage() and main().
 The await keyword appears before calling the asynchronous
functions fetchUserOrder() and createOrderMessage().
Key terms:

 async: You can use the async keyword before a function’s body to mark it as asynchronous.
 async function: An async function is a function labeled with the async keyword.
 await: You can use the await keyword to get the completed result of an asynchronous expression.
The await keyword only works within an async function.

Execution flow with async and await

An async function runs synchronously until the first await keyword. This means that


within an async function body, all synchronous code before the first await keyword
executes immediately.

Example: Execution within async functions

Run the following example to see how execution proceeds within an async function
body. What do you think the output will be?

Future<void> printOrderMessage() async {


print('Awaiting user order...');
var order = await fetchUserOrder();
print('Your order is: $order');
}

Future<String> fetchUserOrder() {
// Imagine that this function is more complex and slow.
return Future.delayed(Duration(seconds: 4), () => 'Large Latte');
}

Future<void> main() async {


countSeconds(4);
await printOrderMessage();
}

// You can ignore this function - it's here to visualize delay time in
this example.
void countSeconds(int s) {
for (var i = 1; i <= s; i++) {
Future.delayed(Duration(seconds: i), () => print(i));
}
}

Output: Awaiting user order... 1 2 3 4 Your order is: Large Latte


After running the code in the preceding example, try reversing lines 2 and 3:

var order = await fetchUserOrder();


print('Awaiting user order...');

Notice that timing of the output shifts, now that print('Awaiting user order') appears
after the first await keyword in printOrderMessage().

Exercise: Practice using async and await

The following exercise is a failing unit test that contains partially completed code
snippets. Your task is to complete the exercise by writing code to make the tests
pass. You don’t need to implement main().

To simulate asynchronous operations, call the following functions, which are


provided for you:

Function Type signature Description

fetchRole() Future<String> fetchRole() Gets a short description of the user’s role.


fetchLoginAmount() Future<int> fetchLoginAmount() Gets the number of times a user has logged in.

Part 1: reportUserRole()
Add code to the reportUserRole() function so that it does the following:

 Returns a future that completes with the following string: "User role: <user role>"
o Note: You must use the actual value returned by fetchRole(); copying and pasting the
example return value won’t make the test pass.
o Example return value: "User role: tester"
 Gets the user role by calling the provided function fetchRole().

Part 2: reportLogins()
Implement an async function reportLogins() so that it does the following:

 Returns the string "Total number of logins: <# of logins>".


o Note: You must use the actual value returned by fetchLoginAmount(); copying and
pasting the example return value won’t make the test pass.
o Example return value from reportLogins(): "Total number of logins: 57"
 Gets the number of logins by calling the provided function fetchLoginAmount().

// Part 1
// You can call the provided async function fetchRole()
// to return the user role.
Future<String> reportUserRole() async {
// TO DO: Your implementation goes here.
}

// Part 2
// Implement reportLogins here
// You can call the provided async function fetchLoginAmount()
// to return the number of times that the user has logged in.
reportLogins(){}

Handling errors

To handle errors in an async function, use try-catch:


try {
var order = await fetchUserOrder();
print('Awaiting user order...');
} catch (err) {
print('Caught error: $err');
}

Within an async function, you can write try-catch clauses the same way you would in
synchronous code.

Example: async and await with try-catch


Run the following example to see how to handle an error from an asynchronous
function. What do you think the output will be?

Future<void> printOrderMessage() async {


try {
var order = await fetchUserOrder();
print('Awaiting user order...');
print(order);
} catch (err) {
print('Caught error: $err');
}
}

Future<String> fetchUserOrder() {
// Imagine that this function is more complex.
var str = Future.delayed(
Duration(seconds: 4),
() => throw 'Cannot locate user order');
return str;
}

Future<void> main() async {


await printOrderMessage();
}
Output: Caught error: Cannot locate user order

Exercise: Practice handling errors

The following exercise provides practice handling errors with asynchronous code,
using the approach described in the previous section. To simulate asynchronous
operations, your code will call the following function, which is provided for you:

Function Type signature Description


fetchNewUsername() Future<String> fetchNewUsername() Returns the new username that you can use to replace an old one.
Use async and await to implement an asynchronous changeUsername() function
that does the following:

 Calls the provided asynchronous function fetchNewUsername() and returns its


result.
o Example return value from changeUsername(): "jane_smith_92"
 Catches any error that occurs and returns the string value of the error.
o You can use the toString() method to stringify
both Exceptions and Errors.

Exercise: Putting it all together

It’s time to practice what you’ve learned in one final exercise. To simulate
asynchronous operations, this exercise provides the asynchronous
functions fetchUsername() and logoutUser():

Function Type signature Description

fetchUsername() Future<String> fetchUsername() Returns the name associated with the current user.

logoutUser() Future<String> logoutUser() Performs logout of current user and returns the username that was logged out.

Write the following:

Part 1: addHello()
 Write a function addHello() that takes a single String argument.
 addHello() returns its String argument preceded by ‘Hello ‘.
Example: addHello('Jon') returns 'Hello Jon'.

Part 2: greetUser()

 Write a function greetUser() that takes no arguments.


 To get the username, greetUser() calls the provided asynchronous function fetchUsername().
 greetUser() creates a greeting for the user by calling addHello(), passing it the username, and returning the
result.
Example: If fetchUsername() returns 'Jenny', then greetUser() returns 'Hello Jenny'.

Part 3: sayGoodbye()

 Write a function sayGoodbye() that does the following:


o Takes no arguments.
o Catches any errors.
o Calls the provided asynchronous function logoutUser().
 If logoutUser() fails, sayGoodbye() returns any string you like.
 If logoutUser() succeeds, sayGoodbye() returns the string '<result> Thanks, see you next time',
where <result> is the String value returned by calling logoutUser().

// Part 1
addHello(){}
// Part 2
// You can call the provided async function fetchUsername()
// to return the username.
greetUser(){}
// Part 3
// You can call the provided async function logoutUser()
// to log out the user.
sayGoodbye(){}
Async Example

Importing Library in Dart

In Dart to get async support you need to import the async library.
import 'dart:async';
 
main(List<String> args) {
 
}

Future
The async library contains something called Future. Future is something that is
based on the observer pattern. If you familiar with Rx or Promises in Javascript you
are good to go.
In simple terms, a Future defines something that will happen in the ‘future’ i.e. in
future a value will be returned to us. Lets see Future in action.
Future is a generic type, i.e. Future<T>, you have to specify what type of value will
we returned in the future.
import 'dart:async';
 
main(List<String> args) {
  getAJoke().then((value) {
    print(value);
  })
  .catchError((error) {
    print('Error');
  });
}
 
Future<String> getAJoke() {
  return new Future<String>(() {
    //Do a long running task. E.g. Network Call.
    //Return the result
    return "This is a joke";
  });
}

We have defined a function named getAJoke that returns a Future<String>. You


create a Future with the new keyword, the Future constructor takes in a function that
return the value of type T. Whatever you return in the anonymous function will be the
retuned value of the Future.
In main we call the getAJoke function which returns Future<String>. We subscribe to
the Future by calling the then functions which registers a callback, called when the
value is emitted by the Future. We also register a catchError to handle any exceptions
occurred during the execution of a Future. In our example we don’t have any
exceptions occurring.
Below is an example where an exceptions occurs.
import 'dart:async';
 
main(List<String> args) {
  getAJoke().then((value) {
    print(value);
  })
  .catchError((error) {
    print('Error');
  });
}
 
Future<String> getAJoke() {
  return new Future<String>(() {
    //Do a long running task. E.g. Network Call.
    //Return the result
    throw new Exception('No joke for you!');
    return "This is a joke";
  });
}

Now in this example the result is returned immediately. But in production you will use
Future to execute some code that takes time, for example, a network call. We can
simulate that behaviour using Future.delayed().
import 'dart:async';
 
main(List<String> args) {
  getAJoke().then((value) {
    print(value);
  })
  .catchError((error) {
    print('Error');
  });
}
 
Future<String> getAJoke() {
  return new Future<String>.delayed(new Duration(milliseconds: 2000),() {
    //Do a long running task. E.g. Network Call.
    //Return the result
    return "This is a joke";
  });
}

Now if your run the program, it will take 2 second to out the result. Let’s see another
example.
import 'dart:async';
 
main(List<String> args) {
  getAJoke().then((value) {
    print(value);
  })
  .catchError((error) {
    print('Error');
  });
  print('Another print statement.');
}
 
Future<String> getAJoke() {
  return new Future<String>.delayed(new Duration(milliseconds: 2000),() {
    //Do a long running task. E.g. Network Call.
    //Return the result
    return "This is a joke";
  });
}

As you can see I have added a print statement after calling the function. In this
scenario, the print statement executes first and after that the value returned from Future
is printed. This is the expected behaviour we want from Future. But, what if we have a
Future and we want to execute it first, before going ahed in for more execution. This is
where async/await comes into action.

Async/Await
import 'dart:async';
 
main(List<String> args) async {
  try {
    String result = await getAJoke();
    print(result);
  } catch(e) {
    print(e);
  }
  print('Another print statement.');
}
 
Future<String> getAJoke() {
  return new Future<String>.delayed(new Duration(milliseconds: 2000),() {
    //Do a long running task. E.g. Network Call.
    //Return the result
    return "This is a joke";
  });
}

As you can see we have added the async keyword before the curly brace of our main
function on line 3 (we will come to that later). We have added await keyword before
calling the getAJoke function, what this does is wait for the result to be returned from
the Future before moving forward. We have wrapped our code in a try/catch block we
want to catch any exception (which we caught before using the catchError callback).
To use the keyword await you will have to mark the function with async keyword, else
it won’t work.
Async Example 2

Async Await in Dart


In a nutshell, you have two keywords to understand - async and await.  Any functions you want to
run asynchronously, needs to have the async modifier added to it.  This modifier comes right after
the function signature, just like this:

void hello() async {


print('something exciting is going to happen here...');
}

This is of course a contrived example.  Typically the function you want to run asynchronously
would have some expensive operation in it - like file i/o, some sort of computation, or more
commonly an API call to a RESTful service.  Don't worry, we'll cover more complex scenarios in a
bit...
And now we come to await.  The await part basically says - go ahead and run this function
asynchronously, and when it is done, continue on to the next line of code.  This is the best part of
using async/await - because you can write code that is very easy to follow, like this:

void main() async {


await hello();
print('all done');
}

There are two important things to grasp concerning the above block of code. First off, we use the
async modifier on the main method because we are going to run the hello() function
asynchronously.  And secondarily we place the await modifier directly in front of the function we
want to run asynchronously.  Hence why this is frequently referred to as the async/await pattern.
Just remember, if you are going to await, make sure both the caller function and any functions you
call within that function all use the async modifier .

How does this work under the hood?


So just how does Dart make this all work?  To really grasp this, you need to understand Dart
Futures.  You can skip this section if you want and still use this pattern, but it does help to have the
knowledge as to how and why this works.  So here are the finer points of how async and await
work in Dart.
 When you await an async function, execution of the code within the caller suspends while the async
operation is executed.
 When an async operation is completed, the value of what was awaited is contained within the Future
Take a look at the simple program below.  We assign the variable x to the result of the
asynchronous function four().  Then we print out its number to prove we got back the expected
result.

import 'dart:async';

void main() async {


var x = await four();
print(x);
}

Future<int> four() async {


return 4;
}
A More Realistic Example
So far I have shown you contrived examples that really never needed to be asynchronous.  This
was done to keep things as simple as possible.  But now lets do some realistic async / await work
here.
Typically, the reason you wanted to do async programming in the first place is because you knew
you were going to perform a long running operation and you didn't want your program to be non-
responsive while that operation was running.  Let's create a long running operation (2 seconds)
and do it async.

import 'dart:async';

class Employee {
int id;
String firstName;
String lastName;

Employee(this.id, this.firstName, this.lastName);


}

void main() async {


print("getting employee...");
var x = await getEmployee(33);
print("Got back ${x.firstName} ${x.lastName} with id# ${x.id}");
}

Future<Employee> getEmployee(int id) async {


//Simluate what a real service call delay may look like by delaying 2 seconds
await Future<Employee>.delayed(const Duration(seconds: 2));

//and then return an employee - lets pretend we grabbed this out of a database
var e = new Employee(id, "Joe", "Coder");
return e;
}

If you run the above code, you see the message "getting employee..." print out immediately. 
Then, 2 seconds later, the employee arrives back and the details of that employee are printed out.

Multiple Async Calls


In some languages, having to make multiple async calls can be a real headache if they don't
support the async / await pattern.  This is because you typically would make the first async call
and within its callback nest another async call, and so on...  This is referred to as "callback hell". 
With async await, you make the calls linearly and without nesting - just like you would non-async
code.  Consider the example below where we have three async methods and we want to call them
in order one at a time and do it asynchronously.

import 'dart:async';

Future<String> firstAsync() async {


await Future<String>.delayed(const Duration(seconds: 2));
return "First!";
}

Future<String> secondAsync() async {


await Future<String>.delayed(const Duration(seconds: 2));
return "Second!";
}

Future<String> thirdAsync() async {


await Future<String>.delayed(const Duration(seconds: 2));
return "Third!";
}

void main() async {


var f = await firstAsync();
print(f);
var s = await secondAsync();
print(s);
var t = await thirdAsync();
print(t);
print('done');
}

If you were to run the above program, you would see the following result shown in your console
(note the 2 second delay as well between each call):

First!
Second!
Third!
done

Having fun with Futures


By now you probably realize that to do async programming in Dart, you'll be working with Futures. 
So it would be good to know your way around that class.  Let's take two scenarios and show how
the Future class in Dart handles them - iterating a list of async calls in order, and waiting for all
async calls to complete.

Iterating
To iterate a set of async calls, use Future.forEach.  In the example below, we create a method to
check if a number is prime or not.  Since we wrap our result coming from isPrimeNumber in a
Future, we are able to await the results and invoke then so that we can perform an operation of our
choosing against that result (which in our case, we just print out the result).
import 'dart:async';
import 'dart:math';

Future<bool> isPrimeNumber(int number) async {


if (number == 1) return false;
if (number == 2) return true;

double mysqrt = sqrt(number);


int limit = mysqrt.ceil();

for (int i = 2; i <= limit; ++i) {


if (number % i == 0) return false;
}

return true;
}

void main() async {


await Future.forEach([1,2,3,4,5,6,7,8,9,10], (int n) =>
isPrimeNumber(n)
.then((x) => print("${n}${x ? " is" : " is not"} a prime number")));

print('done!');
}
Waiting
To execute some code when all async calls have completed, use Future.wait. In the example
below, we generate a handful of random numbers asynchronously.  When all of the random
numbers are generated, we print out the list and find the smallest value.
import 'dart:async';
import 'dart:math';

Future<int> getRandomNumber() async {


var random = new Random();
return random.nextInt(100);
}

void findSmallestNumberInList(List<int> lst) {


print("all numbers are in:");
lst.forEach((l) => print(l));
lst.sort();
int largest = lst.first;
print("The smallest random # we generated was: ${largest}");
}

void main() async {


Future.wait([getRandomNumber(), getRandomNumber(), getRandomNumber()])
.then((List<int> results) => findSmallestNumberInList(results));
}

Error Handling
Dart makes handling errors within asynchronous code easy because it utilizes something you are
already likely very familiar with - try catch blocks.  If the code within a try block throws an
exception, you are going to be able to handle it in the catch block.  In the example below, we
intentionally throw an exception in the openFile function just to show you how this works.  If you
run this, you would see the "success!" message is never printed and instead we see a message
concerning the exception that was thrown.
import 'dart:async';

Future<void> openFile(String fileName) async {


throw new Exception("boom!");
}

void main() async {


try
{
var result = await openFile("theFile");
print("success!");
}
catch(e) {
print("Looks like we caught an error: ${e.toString()}");
}
}

Dart asynchronous programming: Futures


One of the most basic APIs that Dart has for asynchronous programming is futures
— objects of type Future. For the most part, Dart’s futures are very similar to
the future or promise APIs found in other languages.

This article discusses the concepts behind Dart futures and tells you how to use
the Future API. It also discusses the Flutter FutureBuilder widget, which helps
you update a Flutter UI asynchronously, based on the state of a future.

Thanks to Dart language features like async-await, you might never need to use
the Future API directly. But you’re almost certain to encounter futures in your Dart
code. And you might want to create futures or read code that uses the Future API.

You can think of futures as little gift boxes for data. Somebody hands you one of these
gift boxes, which starts off closed. A little while later the box pops open, and inside
there’s either a value or an error.

So a future can be in one of 3 states:

1. Uncompleted: The gift box is closed.

2. Completed with a value: The box is open, and your gift (data) is ready.

3. Completed with an error: The box is open, but something went wrong.

Most of the code you’re about to see revolves around dealing with these three states.
You receive a future, and you need to decide what to do until the box opens, what to
do when it opens with a value, and what to do if there’s an error. You’ll see that 1–2–
3 pattern a lot.

A good thing to know about futures is that they’re really just an API built to make
using the event loop easier.

The Dart code you write is executed by a single thread. The whole time your app is
running, that one little thread just keeps going around and around, picking up events
from the event queue and processing them.

Say you have some code for a download button (implemented below as
a RaisedButton). The user taps, and your button starts downloading a picture.

RaisedButton(
onPressed: () {
final myFuture = http.get('https://my.image.url');
myFuture.then((resp) {
setImage(resp);
});
},
child: Text('Click me!'),
)

First the tap event occurs. The event loop gets the event, and it calls your tap handler
(which you set using the onPressed parameter to the RaisedButton constructor).
Your handler uses the http library to make a request (http.get()), and it gets a
future in return (myFuture).

So now you’ve got your little box, myFuture. It starts off closed. To register a
callback for when it opens, you use then().

Once you have your gift box, you wait. Maybe some other events come in, the user
does some stuff, and your little box just sits there while the event loop keeps going
around.

Eventually, data for the image is downloaded, and the http library says, “Great! I’ve
got this future right here.” It puts the data in the box and pops it open, which triggers
your callback.

Now that little piece of code you handed to then() executes, and it displays the
image.

Throughout that process, your code never had to touch the event loop directly. It
didn’t matter what else was going on, or what other events came in. All you needed to
do was get the future from the http library, and then say what to do when the future
completed.

In real code, you’d also take care of errors. We’ll show you how to do that a little later.

Let’s take a closer look at the Future API, some of which you just saw in use.

OK, first question: how do you get an instance of a Future? Most of the time, you
don’t create futures directly. That’s because many of the common asynchronous
programming tasks already have libraries that generate futures for you.

For example, network communication returns a future:

final myFuture = http.get('http://example.com');

Getting access to shared preferences also returns a future:

final myFuture = SharedPreferences.getInstance();

But you can also use Future constructors to create futures.


Future constructors

The simplest constructor is Future(), which takes a function and returns a future that
matches the function’s return type. Later the function runs asynchronously, and the
future completes with the function’s return value. Here’s an example of
using Future():
void main() {
final myFuture = Future(() {
print('Creating the future.'); // Prints second.
return 12;
});
print('Done with main().'); // Prints first.
}

If you run that code in DartPad, the entire main function finishes before the function
given to the Future() constructor. That’s because the Future() constructor just
returns an uncompleted future at first. It says, “Here’s this box. You hold onto that
for now, and later I’ll go run your function and put some data in there for you.”
Here’s the output of the preceding code:

Done with main().


Creating the future.

Another constructor, Future.value(), is handy when you already know the value


for the future. This constructor is useful when you’re building services that use
caching. Sometimes you already have the value you need, so you can pop it right in
there:

final myFuture = Future.value(12);

The Future.value() constructor has a counterpart for completing with an error.


It’s called Future.error(), and it works essentially the same way, but takes an
error object and an optional stacktrace:

final myFuture = Future.error(ArgumentError.notNull('input'));

The handiest future constructor is probably Future.delayed(). It works just


like Future(), except that it waits for a specified length of time before running the
function and completing the future.

One way to use Future.delayed() is when you’re creating mock network services


for testing. If you need to make sure your loading spinner displays correctly, a
delayed future is your friend.

final myFuture = Future.delayed(


const Duration(seconds: 5),
() => 12,
);
Using futures

Now that you know where futures come from, let’s talk about how to use them. As we
mentioned earlier, using a future is mostly about accounting for the three states it
can be in: uncompleted, completed with a value, or completed with an error.

The following code uses Future.delayed() to create a future that completes after 3


seconds with a value of 100.
void main() {
Future.delayed(
const Duration(seconds: 3),
() => 100,
);
print('Waiting for a value...');
}

When this code executes, main() runs from top to bottom, creating the future and
printing “Waiting for a value…” That whole time, the future is uncompleted. It
doesn’t complete for another 3 seconds.

To use the completed value, you can use then(). That’s an instance method on each
future that you can use to register a callback for when the future completes with a
value. You give it a function that takes a single parameter matching the type of the
future. Once the future completes with a value, your function is called with that
value.
void main() {
Future.delayed(
const Duration(seconds: 3),
() => 100,
).then((value) {
print('The value is $value.'); // Prints later, after 3 seconds.
});
print('Waiting for a value...'); // Prints first.
}
Here’s the output of the preceding code:
Waiting for a value... (3 seconds pass until callback executes)
The value is 100.

In addition to executing your code, then() returns a future of its own, matching the


return value of whatever function you give it. So if you need to make a couple of
asynchronous calls, you can chain them together even if they have different return
types.
_fetchNameForId(12)
.then((name) => _fetchCountForName(name))
.then((count) => print('The count is $count.'));
Back to our first example, what happens if that initial future doesn’t complete with a
value — what if it completes with an error? The then() method expects a value. You
need a way to register another callback in case of an error.

The answer is to use catchError(). It works just like then(), except that it takes


an error instead of a value, and it executes if the future completes with an error. Just
like then(), the catchError() method returns a future of its own, so you can
build a whole chain of then() and catchError()methods that wait on one
another.

Note: You don’t need to call then() or catchError() if you use the async-


await language feature. Instead, you await the completed value, and you use try-
catch-finally to handle errors. For details, see the Dart language tour’s asynchrony
support section.

Here’s an example of using catchError() to handle the case where a future


completes with an error:

void main() {
Future.delayed(
Duration(seconds: 3),
() => throw 'Error!', // Complete with an error.
).then((value) {
print(value);
}).catchError((err) {
print('Caught $err'); // Handle the error.
});
print('Waiting for a value...');
}

You can even give catchError() a test function to check the error before invoking
the callback. You can have multiple catchError() functions this way, each one
checking for a different kind of error. Here’s an example of specifying a test function,
using the optional test parameter to catchError():

void main() {
Future.delayed(
Duration(seconds: 3),
() => throw 'Error!',
).then((value) {
print(value);
}).catchError((err) {
print('Caught $err');
}, test: (err) { // Optional test parameter.
return err is String;
});
print('Waiting for a value...');
}
Now that you’ve gotten this far, hopefully you can see how the three states of a future
are often reflected by the structure of the code. There are three blocks in the
preceding example:

1. The first block creates an uncompleted future.


2. Then there’s a function to call if the future completes with a value.
3. Then there’s another function to call if the future completes with an error.

There’s one more method you might want to use: whenComplete(). You can use it
to execute a function when the future is completed, no matter whether it’s with a
value or an error.

It’s kind of like the finally block in a try-catch-finally. There’s code executed if


everything goes right, code for an error, and code that runs no matter what.

Using futures in Flutter

So that’s how you create futures, and a bit about how you can use their values. Now
let’s talk putting them to work in Flutter.

Say you have a network service that’s going to return some JSON data, and you want
to display that data. You could create a StatefulWidget that creates the future,
checks for completion or error, calls setState(), and generally handles all the
wiring manually.

Or you can use FutureBuilder. It’s a widget that comes with the Flutter SDK. You
give it a future and a builder function, and it automatically rebuilds its children when
the future completes.

The FutureBuilder widget works by calling its builder function, which takes a


context and a snapshot of the current state of the future.
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Use a FutureBuilder.
return FutureBuilder<String>(
future: _fetchNetworkData(),
builder: (context, snapshot) {},
);
}
}
You can check the snapshot to see whether the future completed with an error:
return FutureBuilder<String>(
future: _fetchNetworkData(5),
builder: (context, snapshot) {
if (snapshot.hasError) {
// Future completed with an error.
return Text(
'There was an error',
);
}
throw UnimplementedError("Case not handled yet");
},
);
Otherwise you can check the hasData property to see if it completed with a value:
return FutureBuilder<String>(
future: _fetchNetworkData(5),
builder: (context, snapshot) {
if (snapshot.hasError) {
// Future completed with an error.
return Text(
'There was an error',
);
} else if (snapshot.hasData) {
// Future completed with a value.
return Text(
json.decode(snapshot.data)['field'],
);
}
throw UnimplementedError("Case not handled yet");
},
);
If neither hasError nor hasData is true, then you know you’re still waiting, and you
can output something for that as well.

return FutureBuilder<String>(
future: _fetchNetworkData(5),
builder: (context, snapshot) {
if (snapshot.hasError) {
// Future completed with an error.
return Text(
'There was an error',
);
} else if (snapshot.hasData) {
// Future completed with a value.
return Text(
json.decode(snapshot.data)['field'],
);
} else {
// Uncompleted.
return Text(
'No value yet!',
);
}
},
);

Even in Flutter code, you can see how those three states keep popping up:
uncompleted, completed with value, and completed with error.
Dart asynchronous programming: Streams

This article covers one of the fundamentals of reactive programming: streams, which
are objects of type Stream.

If you’ve read the previous article on futures, you might remember that each future
represents a single value (either an error or data) that it
delivers asynchronously. Streams work similarly, but instead of a single thing, a
stream can deliver zero or more values and errors over time.

If you think about the way a single value relates to an iterator of the same type, that’s
how a future relates to a stream.

Just like with futures, the key is deciding in advance, “Here’s what to do when a piece
of data is ready, and when there’s an error, and when the stream completes.”

Also just like with futures, the Dart event loop is still running the show.

If you’re using the File class’s openRead() method to read data from a file, for


example, that method returns a stream.

Chunks of data are read from disk and arrive at the event loop. A Dart library looks at
them and says, “Ah, I’ve got somebody waiting for this,” adds the data to the stream,
and it pops out in your app’s code.

When another piece of data arrives, in it goes, and out it comes. Timer-based
streams, streaming data from a network socket — they work with the event loop, too,
using clock and network events.

Listening to streams

Let’s talk about how to work with data provided by a stream. Say you have a class that
gives you a stream that kicks out a new integer once per second: 1, 2, 3, 4, 5…

You can use the listen() method to subscribe to the stream. The only required
parameter is a function.

final myStream = NumberCreator().stream;

final subscription = myStream.listen(


(data) => print('Data: $data'),
);

Every time a new value is emitted by the stream, the function gets called and prints
the value:
Data: 1
Data: 2
Data: 3
Data: 4
...
That’s how listen() works.

Important: By default, streams are set up for single subscription. They hold onto
their values until someone subscribes, and they only allow a single listener for their
entire lifespan. If you try to listen to a stream twice, you’ll get an exception.

Fortunately Dart also offers broadcast streams. You can use


the asBroadcastStream() method to make a broadcast stream from a single
subscription one. Broadcast streams work the same as single subscription streams,
but they can have multiple listeners, and if nobody’s listening when a piece of data
is ready, that data is tossed out.

final myStream = NumberCreator().stream.asBroadcastStream();

final subscription = myStream.listen(


(data) => print('Data: $data'),
);

final subscription2 = myStream.listen(


(data) => print('Data again: $data'),
);

Let’s go back to that first listen() call, because there are a couple more things to talk
about.
As we mentioned earlier, streams can produce errors just like futures can. By adding
an onError function to the listen() call, you can catch and process any error.

There’s also a cancelOnError property that’s true by default, but can be set to false to
keep the subscription going even after an error.
And you can add an onDone function to execute some code when the stream is
finished sending data, such as when a file has been completely read.

With all four of those parameters combined — onError, onDone, cancelOnError, and


the required parameter (onData) — you can be ready in advance for whatever
happens.

final subscription = myStream.listen(


(data) {
print('Data: $data');
},
onError: (err) {
print('Error!');
},
cancelOnError: false,
onDone: () {
print('Done!');
},
);

Tip: The little subscription object that listen() returns has some useful methods of


its own. It’s a StreamSubscription, and you can use it to pause, resume, and even
cancel the flow of data.
final subscription = myStream.listen(...);

subscription.pause();
subscription.resume();
subscription.cancel();

Using and manipulating streams


Now that you know how to use listen() to subscribe to a stream and receive data
events, we can talk about what makes streams really cool: manipulating them. Once
you’ve got data in a stream, a lot of operations become fluent and elegant.
Going back to that number stream from earlier, we can use a method called map() to
take each value from the stream and convert it on the fly into something else.
Give map() a function to do the conversion, and it returns a new stream, typed to
match the return value of the function. Instead of a stream of ints, you now have a
stream of strings. You can throw a listen() call on the end, give it the print() function,
and now you’re printing strings directly off the stream, asynchronously, as they
arrive.

NumberCreator().stream
.map((i) => 'String $i')
.listen(print);
/*
OUTPUT:
String 1
String 2
String 3
String 4
*/

There are a ton of methods that you can chain up like this. If you only want to print
the even numbers, for example, you can use where() to filter the stream. Give it a test
function that returns a boolean for each element, and it returns a new stream that
only includes values that pass the test.

NumberCreator().stream
.where((i) => i % 2 == 0)
.map((i) => 'String $i')
.listen(print);
/*
OUTPUT:
String 2
String 4
String 6
String 8
*/

The distinct() method is another good one. If you have an app that uses a Redux
store, that store emits new app state objects in an onChange stream. You can
use map() to convert that stream of state objects to a stream of view models for one
part of the app. Then you can use the distinct() method to get a stream that filters out
consecutive identical values (in case the store kicks out a change that doesn’t affect
the subset of data in the view model). Then you can listen and update the UI
whenever you get a new view model.

myReduxStore.onChange
.map((s) => MyViewModel(s))
.distinct()
.listen( /* update UI */ );

There are a bunch of additional methods built into Dart that you can use to shape
and modify your streams. Plus, when you’re ready for even more advanced stuff,
there’s the async package maintained by the Dart team and available on pub.dev. It
has classes that can merge two streams together, cache results, and perform other
types of stream-based wizardry.

For even more stream magic, take a look at


the stream_transform package.

Creating streams

One advanced topic deserves a mention here, and that’s how to create streams of
your own. Just like with futures, most of the time you’re going to be working with
streams created for you by network libraries, file libraries, state management, and so
on. But you can make your own as well, using a StreamController.

Let’s go back to that NumberCreator we’ve been using so far. Here’s the actual code
for it:

class NumberCreator {
NumberCreator() {
Timer.periodic(Duration(seconds: 1), (t) {
_controller.sink.add(_count);
_count++;
});
}

var _count = 1;
final _controller = StreamController<int>();
Stream<int> get stream => _controller.stream;
}

As you can see, it keeps a running count, and it uses a timer to increment that count
each second. The interesting bit, though, is the stream controller.

A StreamController creates a brand new stream from scratch, and gives you access to
both ends of it. There’s the stream end itself, where data arrives. (We’ve been using
that one throughout this article.)

Stream<int> get stream => _controller.stream;

Then there’s the sink end, which is where new data gets added to the stream:

_controller.sink.add(_count);

NumberCreator here uses both of them. When the timer goes off, it adds the latest
count to the controller’s sink, and then it exposes the controller’s stream with a
public property so other objects can subscribe to it.

Building Flutter widgets using streams


Now that we’ve covered creating, manipulating, and listening to streams, let’s talk
about how to put them to work building widgets in Flutter.

If you saw the previous video on futures, you might remember FutureBuilder. You
give it a future and a builder method, and it builds widgets based on the state of the
future.

For streams, there’s a similar widget called StreamBuilder. Give it a stream and a


builder method, and it will rebuild its children whenever a new value is emitted by
the stream.
StreamBuilder<String>(
stream: NumberCreator().stream.map((i) => 'String $i'),
builder: (context, snapshot) {
/* Build widgets! */
}
)

The snapshot parameter is an AsyncSnapshot, just like with FutureBuilder. You can


check its connectionState property to see if the stream hasn’t yet sent any data or if
it’s completely finished. You can use the hasError property to see if the latest value is
an error. And, of course, you can handle data values.

StreamBuilder<String>(
stream: NumberCreator().stream.map((i) => 'String $i'),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Text('No data yet.');
} else if (snapshot.connectionState == ConnectionState.done) {
return Text('Done!');
}
}
)

The main thing is just to make sure your builder knows how to handle all the possible
states of the stream. Once you’ve got that, it can react to whatever the stream does.

Dart – Isolates

In this post we will explore how to create an Isolate in Dart. Think of an Isolate as a
worker process you can create to execute code but does not share memory with the
process that spawned it - as the name implies it is isolated and has its own memory
heap.  So how do you communicate with an Isolate?  This is where messages come
into play.  Isolates have both a sending and receiving port from which you can send
and receive information.

Github: Using Isolates in Flutter

Why use an Isolate?

On the surface an Isolate might just seem like another way of executing a task in an
asynchronous manner (see my Dart tutorial on async here for more on that) but
there is a key difference. Async operations in Dart operate on the same thread as the
user interface whereas an Isolate gets its own thread.  Therefore, if you want to
execute a process that is fairly intense and you want to make sure you keep your app
responsive and snappy in the eyes of the user, then you should consider using
Isolates.

How to create and start an Isolate

To create an isolate, you may use the spawn method.  At a minimum, you must give
the spawn method an 'entry point' method with a single parameter.  It is very typical
that this parameter represents the port which the isolate should use to send back
notification messages.  Here is the simplest of examples:

Isolate isolate;

void start() async {


ReceivePort receivePort= ReceivePort(); //port for this main isolate to receive messages.
isolate = await Isolate.spawn(runTimer, receivePort.sendPort);
receivePort.listen((data) {
stdout.write('RECEIVE: ' + data + ', ');
});
}

void runTimer(SendPort sendPort) {


int counter = 0;
Timer.periodic(new Duration(seconds: 1), (Timer t) {
counter++;
String msg = 'notification ' + counter.toString();
stdout.write('SEND: ' + msg + ' - ');
sendPort.send(msg);
});
}
In the example above, we have our start() method which creates a port and spawns
an isolate.  Our start method is marked as async so that we can await the response
from the spawning of the isolate and so that we can store a reference to the new
isolate (this becomes important later when we cover how to kill a running isolate). 
Note that we are giving the spawn call two things - a callback function to execute - in
this case runTimer(), and a port (sendPort) which the callback can use to send
messages back to the caller.  Ports are how you communicate with your isolate and
although we set this up to be one way communication (from the isolate back to the
caller) it can be two-way.  The last thing we do in the start() method is to begin
listening on the receivePort for messages from the isolate.  Whenever we receive a
message, we write it out to the console.

Next, take a look at the runTimer method.  This method starts up a periodic
Timer that fires every second in order to update a counter and send out a
notification message via the port which it received when the isolate was spawned.  If
you were to run this code as a console application, you would see the following
output:
SEND: notification 1 - RECEIVE: notification 1, SEND: notification 2 - RECEIVE:
notification 2

Stopping an Isolate and cleanup

The isolate that we spawned above could go on for an indefinite amount of time. 
This is because we created a timer that wakes up every second with no end in sight. 
But what if we wanted to stop it?  In order to stop an isolate, you would use
the kill method.

void stop() {
if (isolate != null) {
stdout.writeln('killing isolate');
isolate.kill(priority: Isolate.immediate);
isolate = null;
}
}
The above code kills the running isolate and sets the reference to null.  The priority
of Isolate.immediate will cleanly shut down the isolate at the nearest opportunity.

Putting it all together


Let's create a main entry point to call our start() method and also our new stop()
method.  Here is the complete working example.
import 'dart:io';
import 'dart:async';
import 'dart:isolate';

Isolate isolate;

void start() async {


ReceivePort receivePort= ReceivePort(); //port for this main isolate to receive messages.
isolate = await Isolate.spawn(runTimer, receivePort.sendPort);
receivePort.listen((data) {
stdout.write('RECEIVE: ' + data + ', ');
});
}

void runTimer(SendPort sendPort) {


int counter = 0;
Timer.periodic(new Duration(seconds: 1), (Timer t) {
counter++;
String msg = 'notification ' + counter.toString();
stdout.write('SEND: ' + msg + ' - ');
sendPort.send(msg);
});
}

void stop() {
if (isolate != null) {
stdout.writeln('killing isolate');
isolate.kill(priority: Isolate.immediate);
isolate = null;
}
}

void main() async {


stdout.writeln('spawning isolate...');
await start();
stdout.writeln('press enter key to quit...');
await stdin.first;
stop();
stdout.writeln('goodbye!');
exit(0);
}

To execute the above program, you simply need to execute the command 'dart
main.dart' (assuming main.dart is the name of the file you saved the above example
as...).  Make sure of course dart.exe is found on your path first!  You should see
something similar to the below output when running the program:
spawning isolate...
press enter key to quit...
SEND: notification 1 - RECEIVE: notification 1, SEND: notification 2 - RECEIVE:
notification 2, SEND: notification 3 - RECEIVE: notification 3,
killing isolate
goodbye!

Example: Isolates

import 'dart:async';
import 'dart:isolate';

main() async {
var receivePort = new ReceivePort();
await Isolate.spawn(echo, receivePort.sendPort);

// The 'echo' isolate sends it's SendPort as the first message


var sendPort = await receivePort.first;

var msg = await sendReceive(sendPort, "foo");


print('received $msg');
msg = await sendReceive(sendPort, "bar");
print('received $msg');
}

// the entry point for the isolate


echo(SendPort sendPort) async {
// Open the ReceivePort for incoming messages.
var port = new ReceivePort();

// Notify any other isolates what port this isolate listens to.
sendPort.send(port.sendPort);

await for (var msg in port) {


var data = msg[0];
SendPort replyTo = msg[1];
replyTo.send(data);
if (data == "bar") port.close();
}
}

/// sends a message on a port, receives the response,


/// and returns the message
Future sendReceive(SendPort port, msg) {
ReceivePort response = new ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
$ isolates.dart
received foo
received bar

Example 2: Isolates

import 'dart:async';
import 'dart:isolate';

main() async {

// create a long-lived port for receiving messages


var ourFirstReceivePort = new ReceivePort();

// spawn an 'echo' actor, then 'await' for it to reply.


// 'echo' is the name of a function below;
// see its source code to see how it works.
await Isolate.spawn(echo, ourFirstReceivePort.sendPort);

// the 'echo' isolate sends us its SendPort as its first message.


// this lets us communicate with it. we’ll always use this port to
// send it messages.
var echoPort = await ourFirstReceivePort.first;

// if you try to use our first receive port, you’ll get this error:
// “Bad state: Stream has already been listened to.”
// so it seems like you always need a new port to communicate with
// an isolate (actor).
var ourSecondReceivePort = ReceivePort();
echoPort.send(['message 1', ourSecondReceivePort.sendPort]);
var msg = await ourSecondReceivePort.first;
print('main received "$msg"');

// instead of 'await', use 'then' as a different way of receiving


// a reply from 'echo' (handle it asynchronously, rather than
// waiting for the reply)
var port3 = ReceivePort();
echoPort.send(['message 2', port3.sendPort]);
port3.first.then((msg) {
print('main received "$msg"');
});

// use 'then' one more time


var port4 = ReceivePort();
echoPort.send(['port 4', port4.sendPort]);
port4.first.then((msg) {
print('main received "$msg"');
});

print('end of main');

// `echo` is an async function, and it works a little like


// the equivalent of an Akka actor.
echo(SendPort sendPort) async {

// open our receive port. this is like turning on


// our cellphone.
var ourReceivePort = ReceivePort();

// tell whoever created us what port they can reach us on


// (like giving them our phone number)
sendPort.send(ourReceivePort.sendPort);

// listen for text messages that are sent to us,


// and respond to them with this algorithm
await for (var msg in ourReceivePort) {
var data = msg[0]; // the 1st element we receive should
be their message
print('echo received "$data"');
SendPort replyToPort = msg[1]; // the 2nd element should be their
port

// add a little delay to simulate some work being done


Future.delayed(const Duration(milliseconds: 100), () {
// send a message back to the caller on their port,
// like calling them back after they left us a message
// (or if you prefer, they sent us a text message, and
// now we’re texting them a reply)
replyToPort.send('echo said: ' + data);
});

// you can close the ReceivePort if you want


//if (data == "bye") ourReceivePort.close();
}
}

Program output

The output from this Dart isolates example looks like this:

echo received "message 1"


main received "echo said: message 1"
echo received "message 2"
end of main
echo received "port 4"
main received "echo said: message 2"
main received "echo said: port 4"

As the output shows, when I use await with the first message, the initial output is
printed in synchronous order. But once I start using then with “message 2” and “port
4”, those replies are received asynchronously, after “end of main” is printed.

Personally, I prefer the then approach because it reminds me of what I’m


comfortable with when using Scala Futures, but the Dart/Flutter documentation
seems to prefer using await, so I thought I’d show both examples.
Information about FLUTTER

What is Flutter?
The Flutter mobile app SDK is a new way to build beautiful native mobile apps that
break away from the “cookie cutter” apps that have been so common in the past.
People who try Flutter really like it; for example, see this, this, or this. Or here’s a list of
articles and videos compiled by a third party.
As with any new system, people want to know what makes Flutter different, or put
another way, “what is new and exciting about Flutter?” That is a fair question, and this
article will try to answer it from a technical viewpoint — not just what is exciting, but why.
But first, a little history.
A brief history of mobile app development
Mobile app development is a relatively recent field of endeavor. Third-party developers
have been able to build mobile apps for less than a decade, so it is no surprise that
tools are still evolving.
The Platform SDKs
The Apple iOS SDK was released in 2008 and the Google Android SDK in 2009. These
two SDKs were based on different languages: Objective-C and Java, respectively.

Your app talks to the platform to create widgets, or access services like the camera.
The widgets are rendered to a screen canvas, and events are passed back to the
widgets. This is a simple architecture, but you pretty much have to create separate
apps for each platform because the widgets are different, not to mention the native
languages.
WebViews
The first cross-platform frameworks were based on JavaScript and WebViews.
Examples include a family of related frameworks: PhoneGap, Apache Cordova, Ionic,
and others. Before Apple released their iOS SDK they encouraged third party
developers to build webapps for the iPhone, so building cross-platform apps using web
technologies was an obvious step.
Your app creates HTML and displays it in a WebView on the platform. Note that it is
difficult for languages like JavaScript to talk directly to native code (like the services) so
they go through a “bridge” that does context switches between the JavaScript realm
and the native realm. Because platform services are typically not called all that often,
this did not cause too many performance problems.
Reactive Views
Reactive web frameworks like ReactJS (and others) have become popular, mainly
because they simplify the creation of web views through the use of programming
patterns borrowed from reactive programming. In 2015, React Native was created to
bring the many benefits of reactive-style views to mobile apps.

React Native is very popular (and deserves to be), but because the JavaScript realm
accesses the platform widgets in the native realm, it has to go through the bridge for
those as well. Widgets are typically accessed quite frequently (up to 60 times a second
during animations, transitions, or when the user “swipes” something on the screen with
their finger) so this can cause performance problems. As one article about React
Native puts it:
Here lies one of the main keys to understanding React Native performance. Each realm by itself is
blazingly fast. The performance bottleneck often occurs when we move from one realm to the other. In
order to architect performant React Native apps, we must keep passes over the bridge to a minimum.

Flutter
Like React Native, Flutter also provides reactive-style views. Flutter takes a different
approach to avoiding performance problems caused by the need for a JavaScript
bridge by using a compiled programming language, namely Dart. Dart is compiled
“ahead of time” (AOT) into native code for multiple platforms. This allows Flutter to
communicate with the platform without going through a JavaScript bridge that does a
context switch. Compiling to native code also improves app startup times.
The fact that Flutter is the only mobile SDK that provides reactive views without
requiring a JavaScript bridge should be enough to make Flutter interesting and worth
trying, but there is something far more revolutionary about Flutter, and that is how it
implements widgets.
Widgets
Widgets are the elements that affect and control the view and interface to an app. It is
not an overstatement to say that the widgets are one of the most important parts of a
mobile app. In fact, widgets alone can make or break an app.

 The look and feel of widgets is paramount. Widgets need to look good, including


on various screen sizes. They also need to feel natural.
 Widgets must perform fast: to create the widget tree, inflate the widgets
(instantiating their children), lay them out on the screen, render them, or (especially)
animate them.
 For modern apps, widgets should be extensible and customizable. Developers
want to be able to add delightful new widgets, and customize all widgets to match the
app’s brand.

Flutter has a new architecture that includes widgets that look and feel good, are fast,
and are customizable and extensible. That’s right, Flutter does not use the platform
widgets (or DOM WebViews), it provides its own widgets.
Flutter raises the widgets and renderer from the platform into the app, which allows
them to be customizable and extensible. All that Flutter requires of the platform is a
canvas in which to render the widgets so they can appear on the device screen, and
access to events (touches, timers, etc.) and services (location, camera, etc.).
There is still an interface between the Dart program (in green) and the native platform
code (in blue, for either iOS or Android) that does data encoding and decoding, but this
can be orders of magnitude faster than a JavaScript bridge.
Moving the widgets and the renderer into the app does affect the size of the app. The
minimum size of a Flutter app on Android is approximately 4.7MB, which is similar to
minimal apps built with comparable tools. It is up to you to decide if the benefits of
Flutter are worth any tradeoff, so the rest of this article discusses these benefits.
Layout
One of the biggest improvements in Flutter is how it does layout. Layout determines
the size and position of widgets based on a set of rules (also called constraints).
Traditionally, layout uses a large set of rules that can be applied to (virtually) any
widget. The rules implement multiple layout methods. Let’s take as an example CSS
layout because it is well known (although layout in Android and iOS is basically similar).
CSS has properties (the rules), which are applied to HTML elements (the widgets).
CSS3 defines 375 properties.
CSS includes a number of layout models, including (multiple) box models, floating
elements, tables, multiple columns of text, paged media, and so on. Additional layout
models, like flexbox and grid, were added later because developers and designers
needed more control over layout and were using tables and transparent images to get
what they wanted. In traditional layout new layout models cannot be added by the
developer, so flexbox and grid had to be added to CSS and implemented on all
browsers.
Another problem with traditional layout is that the rules can interact (and even conflict)
with each other, and elements often have dozens of rules applied to them. This makes
layout slow. Even worse, layout performance is typically of order N-squared, so as the
number of elements increases, layout slows down even more.
Flutter started as an experiment performed by members of the Chrome browser team
at Google. We wanted to see if a faster renderer could be built if we ignored the
traditional model of layout. After a few weeks, we had achieved significant performance
gains. We discovered:

 Most layout is relatively simple, such as: text on a scrolling page, fixed rectangles
whose size and position depend only on the size of the display, and maybe some
tables, floating elements, etc.
 Most layout is local to a subtree of widgets, and that subtree typically uses one
layout model, so only a small number of rules need to be supported by those widgets.

We realized that layout could be simplified significantly if we turned it on its head:

 Instead of having a large set of layout rules that could be applied to any widget,
each widget would specify its own simple layout model.
 Because each widget has a much smaller set of layout rules to consider, layout
can be optimized heavily.
 To simplify layout even further, we turned almost everything into a widget.
Here’s Flutter code to create a simple widget tree with layout:
new Center(
child: new Column(
children: [
new Text('Hello, World!')),
new Icon(Icons.star, color: Colors.green)
]
)
)
This code is semantic enough that you can easily imagine what it will produce, but
here’s the resulting display:

In this code everything is a widget, including the layout. The Center widget centers its


child inside its parent (for example, the screen). The Column layout widget arranges its
children (a list of widgets) vertically. The column contains a Text widget and
an Icon widget (which does have a property, its color).
In Flutter, centering and padding are widgets. Themes are widgets, which apply to their
children. And even applications and navigation are widgets.
Flutter includes quite a few widgets for doing layout, not just columns but also rows,
grids, lists, etc. In addition, Flutter has a unique layout model we call the “sliver layout
model” which is used for scrolling. Layout in Flutter is so fast it can be used for
scrolling. Think about that for a moment. Scrolling must be so instantaneous and
smooth that the user feels like the screen image is attached to their finger as they drag
it across the physical screen.
By using layout for scrolling, Flutter can implement advanced kinds of scrolling, like
these shown below. Note that these are animated GIF images, Flutter is even
smoother. You can (and should!) run these apps yourself; see the Resources section at
the end of this article.

Most of the time, Flutter can do layout in a single pass, which means in linear time, so it
can handle large numbers of widgets. Flutter also does caching and other things so it
can avoid doing layout at all, when possible.
Custom design
Because widgets are now part of the app, new widgets can be added and existing
widgets can be customized to give them a different look or feel, or to match a
company’s brand. The trend in mobile design is away from the cookie cutter apps that
were common a few years ago and toward custom designs that delight users and win
awards.
Flutter comes with rich, customizable widget sets for Android, iOS, and Material
Design (in fact, we have been told that Flutter has one of the highest fidelity
implementations of Material Design). We used the customizability of Flutter to build
these widget sets, to match the look and feel of native widgets on multiple platforms.
App developers can use the same customizability to further tweak widgets to their
wants and needs.
More about Reactive Views
Libraries for reactive web views introduced virtual DOM. DOM is the HTML Document
Object Model, an API used by JavaScript to manipulate an HTML document,
represented as a tree of elements. Virtual DOM is an abstract version of the DOM
created using objects in the programming language, in this case JavaScript.
In reactive web views (implemented by systems like ReactJS and others) the virtual
DOM is immutable, and is rebuilt from scratch each time anything changes. The virtual
DOM is compared to the real DOM to generate a set of minimal changes, which are
then executed to update the real DOM. Finally, the platform re-renders the real DOM
and paints it into a canvas.

This may sound like an awful lot of extra work, but it is well worth it
because manipulating the HTML DOM is very expensive.
React Native does a similar thing, but for mobile apps. Instead of DOM, it manipulates
the native widgets on the mobile platform. Instead of a virtual DOM, It builds a virtual
tree of widgets and compares it to the native widgets and only updates those that have
changed.

Remember that React Native has to communicate with the native widgets through the
bridge, so the virtual tree of widgets helps keep passes over the bridge to a minimum,
while still allowing the use of native widgets. Finally, once the native widgets are
updated, the platform then renders them to the canvas.
React Native is a big win for mobile development, and was an inspiration for Flutter, but
Flutter takes this a step further.
Recall that in Flutter, the widgets and the renderer have been lifted up out of the
platform into the user’s app. There are no native platform widgets to manipulate, so
what was a virtual widget tree is now the widget tree. Flutter renders the widget tree
and paints it to a platform canvas. This is nice and simple (and fast). In addition,
animation happens in user space, so the app (and thus the developer) have more
control over it.
The Flutter renderer itself is interesting: it uses several internal tree structures to render
only those widgets that need to be updated on the screen. For example, the renderer
uses “structural repainting using compositing” (“structural” meaning by widget, which is
more efficient than doing it by rectangular areas on the screen). Unchanged widgets,
even those that have moved, are “bit blitted” from cache, which is super fast. This is
one of the things that makes scrolling so performant in Flutter, even in advanced
scrolling (discussed and shown above).
For a closer look at the Flutter renderer, I recommend this video. You can also look at
the code, because Flutter is open source. And of course, you can customize or even
replace the whole stack, including the renderer, compositor, animation, gesture
recognizer, and (of course) the widgets.
The Dart programming language
Because Flutter — like other systems that use reactive views — refreshes the view tree
for every new frame, it creates many objects that may live for only one frame (a sixtieth
of a second). Fortunately, Dart uses “generational garbage collection” that is very
efficient for these kind of systems, because objects (especially short-lived ones) are
relatively cheap. In addition, allocation of objects can be done with a single pointer
bump, which is fast and doesn’t require locks. This helps avoid UI jank and stutter.
Dart also has a “tree shaking” compiler, which only includes code that you need in your
app. You can feel free to use a large library of widgets even if you only need one or two
of them.
For more information about Dart, read “Why Flutter uses Dart”.
Hot reload
One of the most popular features of Flutter is its fast, stateful hot reload. You can make
a change to a Flutter app while it is running, and it will reload the app’s code that has
changed and let it continue from where it left off, often in less than a second. If your app
encounters an error, you can typically fix the error and then continue on as if the error
never happened. Even when you have to do a full reload, it is fast.

Developers tell us that this lets them “paint” their app, making one change at a time and
then seeing the results almost instantly, without having to restart the app.
Compatibility
Because widgets (and the renderer for those widgets) are part of your app, not the
platform, no “compat libraries” are needed. Your apps will not only work, but they will
work the same on recent OS versions — Android Jelly Bean and newer and iOS 8.0 and
newer. This significantly reduces the need to test apps on older OS versions. Plus it is
likely that your apps will work on future OS versions.
There is one potential concern that we get asked about. Because Flutter doesn’t use
the native platform widgets, will it take long for the Flutter widgets to be updated when a
new version of iOS or Android comes out that supports a new kind of widget, or
changes the look or behavior of an existing widget?
 First of all, Google is a big internal user of Flutter, so we have a strong incentive
to update the widget sets to keep them current and as close to the current platform
widgets as possible.
 If there is ever a time when we are too slow in updating a widget, Google isn’t the
only user of Flutter with an incentive to keep the widgets current. Flutter’s widgets are
so extensible and customizable that anyone can update them, even you. One doesn’t
even have to file a pull request. You will never have to wait for Flutter itself to be
updated.
 And the above points apply only if you want to have the new change reflected in
your app. If you don’t want a change to affect the way your app looks or behaves,
you’re good. Widgets are part of your app, so a widget will never change out from
under you and make your app look bad (or worse, break your app).
 As an added benefit, you can write your app so it uses the new widget even on
older OS versions.
Other benefits
Flutter’s simplicity makes it fast, but it is the pervasive customizability and extensibility
that makes it powerful.
Dart has a repository of software packages so you can extend the capabilities of your
apps. For example, there are a number of packages that make it easy to access
Firebase so you can build a “serverless” app. An outside contributor has created a
package that lets you access a Redux data store. There are also packages called
“plugins” that make it easier to access platform services and hardware, such as the
accelerometer or the camera, in an OS-independent way.
Of course, Flutter is also open source, which coupled with the fact that the Flutter
rendering stack is part of your app, means that you can customize almost anything you
want for an individual app. Everything in green in this figure can be customized:

So, “What’s new and exciting about Flutter?”


If anyone asks you about Flutter, now you know how to answer them:

 The advantages of reactive views, with no JavaScript bridge


 Fast, smooth, and predictable; code compiles AOT to native (ARM) code
 The developer has full control over the widgets and layout
 Comes with beautiful, customizable widgets
 Great developer tools, with amazing hot reload
 More performant, more compatibility, more fun

Did you notice what I left off this list? It is something that is usually the first thing people
mention when they talk about Flutter, but to me it is one of the least interesting things
about Flutter.
It is the fact that Flutter can build beautiful and fast apps for multiple platforms from a
single codebase. Of course, that should be a given! It is customizability and extensibility
that makes it easy to target Flutter to multiple platforms without giving up performance
or power.
Revolutionary
I also never fully explained why Flutter is “revolutionary”. It just seems fitting, because
one of the first major apps built with Flutter by outside developers is the official app for
“Hamilton: An American Musical”, which takes place around the time of the American
Revolutionary War. Hamilton is one of the most popular Broadway musicals of all time.

The agency, Posse, says they picked Flutter because they needed to build the app “in
only three short months”. They call it “A revolutionary app for a revolutionary show” and
say “Flutter is an excellent choice for beautiful, high-performance, brand-driven mobile
experiences.” They also gave a talk at the Google Developer Days conference on their
experience building an app with Flutter. The app is available on Android and iOS,
and received rave reviews.
Join the Revolution!
On December 4, 2018, Flutter 1.0 was released. We will continue to add more features
to it, and we have more optimizations planned. Use of Flutter has taken off, with more
than 250,000 developers around the world. Flutter is currently in the top 20 on Github
for active software repositories.
If you are interested in Flutter, you can install it and play around with some sample
apps that come with the installation. Be sure to check out the stateful hot reload.
If you aren’t a developer or just want to see some apps, you can install apps built with
Flutter and see how they look and perform. I recommend the Hamilton app, but there
are others. You should also watch the video from Google I/O where they live code a
Flutter app.
Resources

 Watch the Flutter videos from Google I/O 2018


 Watch the videos from DartConf 2018, held January 23–24, 2018 in Los Angeles,
California
 Introducing Flutter video.

Websites:

 The Flutter website
 The source repositories (pull requests welcome!)
 More helpful links
 Gitter channel

Videos:

 Experience building the Hamilton app, at GDD


 Live coding a Flutter app, at Google I/O
 Live coding with a designer, at Google I/O
 “Flutter, a new hope” at Droidcon Italy
 “The Flutter rendering pipeline”

Apps:

 The app for Hamilton: An American Musical


 Flutter Gallery: for Android, on Github (also included in the flutter install at
examples/flutter_gallery)
 Posse Gallery
 Friendlychat: first codelab, Firebase codelab, on Github

You might also like