This is the first article on learning from Scratch to develop a Flutter App.

This article introduces the basic features of Dart. The purpose of this article is to give you a general understanding of the Dart language and a preliminary grasp of the Dart syntax.

We assume that you already have some programming background, and if you know an object-oriented language like JavaScript or Java, Dart should be very hands-on to learn.

Dart is a programming language that takes a broad approach. Although Dart has a lot of syntax similar to JavaScript, it is also a strongly typed language that combines features of strongly typed object-oriented languages like Java to make it suitable for large-scale application development without the bloat of Java. The Dart language is simple, flexible, and efficient in design.

From simple browser script to nodeJS, JavaScript gradually extends to PC client (electron), App (React Native) and even small program development. It has become a full-stack development language in a real sense.

If JavaScript has grown barbarously over time, Dart was carefully designed from the start. If there’s one language to take JavaScript’s place, it’s probably Dart.

Talk is Cheep, let’s take a look at the language for ourselves.

variable

You can declare a variable like JavaScript:

var name = 'Bob';
Copy the code

The compiler deduces that name is of type String, equivalent to:

String name = 'Bob';
Copy the code

Dart is a strongly typed language, as shown in the following code:

var name = 'Bob';
  
// Call the String method
print(name.toLowerCase());

// Error compiling
// name = 1;
Copy the code

As we mentioned earlier, Dart can also be very flexible. If you want to change the type of a variable, you can also use dynamic to declare the variable, just like JavaScript:

dynamic name = 'Bob'; / / type String
name = 1;/ / int type
print(name);
Copy the code

The code above compiles and runs fine, but don’t use it unless you have a good reason to.

Final has the same semantics as Java, meaning that the variable is immutable:

// String can be omitted
final String name = 'Bob'; 

// Error compiling
// name = 'Mary';
Copy the code

Where String can be omitted, the Dart compiler is smart enough to know the type of the variable name.

If you want to declare constants, you can use the const keyword:

const PI = '3.14';

class Person{
  static const name = 'KK';
}

Copy the code

If it is a class variable, it needs to be declared static const.

Built-in types

Unlike Java, the type is particularly detailed, such as the integer type, byte, short, int, long. One of the things that makes Dart easy to use is its simplicity of type design, which can be interpreted as sacrificing space for efficiency.

Numeric types

Dart has built-in support for two numeric types, int and double, both 64-bit in size.

var x = 1;
// 0x starts with a hexadecimal integer
var hex = 0xDEADBEEF;


var y = 1.1;
// in exponential form
var exponents = 1.42 e5;
Copy the code

Note that in Dart, all variable values are an object, including int and double, which are subclasses of num, unlike Java and JavaScript:

// 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');
Copy the code

string

The Dart string uses UTF-16 encoding.

var s = 'in';
s.codeUnits.forEach((ch) => print(ch));
// Outputs UNICODE values
20013
Copy the code

Dart uses JavaScript’s template-like string concept to insert variables in strings using the ${expression} syntax:

var s = "hello";
  
print('${s}, world! ');
  
// Can be simplified to:
print('$s, world! ');

// Call the method
print('${s.toUpperCase()}, world! ');
Copy the code

Dart can compare strings directly with == :

var s1 = "hello";
var s2 = "HELLO";
assert(s1.toUpperCase() == s2);
Copy the code

Boolean type

The Dart Boolean type corresponds to the bool keyword, which has true and false values, similar to those of other languages. It’s worth noting that Dart conditional statements like if and assert must have bool values, unlike JavaScript.

var s = ' ';
assert(s.isEmpty);

if(s.isNotEmpty){
// do something
}
  
// compiler error, used in JavaScript to identify undefined
if(s){
}
Copy the code

Lists

You can map a List in Dart to a JavaScript array or an ArrayList in Java, but Dart is more elaborate.

You can declare an array object like JavaScript:

var list = [];
list.add('Hello');
list.add(1);
Copy the code

Here the List accepts type Dynamic, and you can add any type of object to it, but declare it like this:

var iList = [1.2.3];
iList.add(4);
The argument type 'String' can't be assigned to The parameter type 'int'
//iList.add('Hello');
Copy the code

Dart then deduces that the List is a List

, from which the List can only accept ints. You can also explicitly declare the type of the List:

var sList = List<String> ();// In the Flutter library, there are many variable declarations like this:
List<Widget> children = const <Widget>[];
Copy the code

Const const = ‘children’; const const = ‘children’; const = ‘children’; const = ‘children’;

var constList = const <int> [1.2];
constList[0] = 2; // Compile passed, run error
constList.add(3); // Compile passed, run error
Copy the code

Dart2.3 added the spread operator… And… ? You can easily see how they are used in this example:

var list = [1.2.3];
var list2 = [0. list];assert(list2.length == 4);
Copy the code

If the extension object may be NULL, you can use… ? :

 var list;
 var list2 = [0. ? list];assert(list2.length == 1);
Copy the code

You can determine whether an element is needed directly within the element:

var promoActive = true;
var nav = [
    'Home'.'Furniture'.'Plants',
    promoActive? 'About':'Outlet'
];
Copy the code

Even use for to dynamically add multiple elements:

var listOfInts = [1.2.3];
var listOfStrings = [
  '# 0'.for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] = ='# 1');
Copy the code

This dynamic capability makes Flutter very convenient when building Widget trees.

Sets

The semantics of Set are the same as those of other languages, meaning that the object in the container is unique. In Dart, Set defaults to the LinkedHashSet implementation, indicating that elements are sorted in the order they were added.

Declare the Set object:

var halogens = {'fluorine'.'chlorine'.'bromine'.'iodine'.'astatine'};
Copy the code

Iterate over Set, iterate over except for the above mentioned for… In, you can also use the forEach form of the Java-like lambada:

halogens.add('bromine');
halogens.add('astatine');
halogens.forEach((el) => print(el));
Copy the code

Output result:

fluorine
chlorine
bromine
iodine
astatine
Copy the code

Except for the object uniqueness of the container, it is basically the same as a List.

// Add a type declaration:
var elements = <String> {};var promoActive = true;
// Add elements dynamically
final navSet = {'Home'.'Furniture', promoActive? 'About':'Outlet'};
Copy the code

Maps

Map objects are declared in JavaScript fashion, and the default implementation of a Map in Dart is LinkedHashMap, which represents elements in the order in which they were added.

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

assert(gifts['first'] = ='partridge');
Copy the code

Add a key-value pair:

gifts['fourth'] = 'calling birds';
Copy the code

Through the Map:

gifts.forEach((key,value) => print('key: $key, value: $value'));
Copy the code

function

In Dart, the Function itself is also an object, and its corresponding type is Function, which means that functions can be passed as variable values or parameter values as a method.

void sayHello(var name){
  print('hello, $name');
}

void callHello(Function func, var name){
  func(name);
}

void main(){
  // Function variable
  var helloFuc = sayHello;
  // Call the function
  helloFuc('Girl');
  // Function arguments
  callHello(helloFuc,'Boy');
}
Copy the code

Output:

hello, Girl
hello, Boy
Copy the code

For simple functions with only one expression, you can also make the function more concise by using =>, => expr is equivalent to {return expr; }, let’s look at the following statement:

String hello(var name ) => 'hello, $name';
Copy the code

Is equivalent to:

String hello(var name ){
  return 'hello, $name';
}
Copy the code

parameter

Named parameters can be found everywhere in the Flutter UI library. Here is an example of using Named parameters:

void enableFlags({bool bold, boolhidden}) {... }Copy the code

Call this function:

enableFlags(bold: false);
enableFlags(hidden: false);
enableFlags(bold: true, hidden: false);
Copy the code

Named parameters are optional by default. If you want to indicate that the parameter must be passed, use @required:

void enableFlags({bool bold, @required bool hidden}) {}
Copy the code

Of course, Dart also supports generic functional forms:

void enableFlags(bool bold, bool hidden) {}
Copy the code

Unlike named arguments, arguments of this form are passed by default:

enableFlags(false.true);
Copy the code

You can use [] to add non-mandatory arguments:

void enableFlags(bool bold, bool hidden, [bool option]) {}
Copy the code

In addition, the Dart function also supports setting parameter defaults:

void enableFlags({bool bold = false.bool hidden = false{...}) }String say(String from, [String device = 'carrier pigeon'.String mood]) {}
Copy the code

Anonymous functions

By definition, an anonymous function is a function that has no defined name. If you’re familiar with this, we’ve already used it when iterating through lists and maps. Anonymous functions can simplify code even further:

var list = ['apples'.'bananas'.'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});
Copy the code

closure

Dart supports closures. For those of you who are not familiar with JavaScript, closures may be unfamiliar. Here’s a quick explanation of closures.

Closures are tricky to define, so instead of trying to define them, we’ll try to understand them with an example:

Function closureFunc() {
  var name = "Flutter"; // Name is a local variable created by init
  void displayName() { // displayName() is an inner function, a closure
    print(name); // Use a variable declared in the parent function
  }
  return displayName;
}

void main(){
  MyFunc is a displayName function
  var myFunc = closureFunc(); / / (1)
  
  // Execute the displayName function
  myFunc(); / / (2)
}
Copy the code

The result was to print Flutter as we expected.

After (1), name is a local variable to a function, and the referenced object should be recycled. But when we call an external name from an inner function, it still magically gets called. Why?

This is because Dart runs internal functions in a closure that is a combination of the function and the lexical environment that created the function, which contains all the local variables that the closure was created to access.

Let’s change the code briefly:

Function closureFunc() {
  var name = "Flutter"; // Name is a local variable created by init
  void displayName() { // displayName() is an inner function, a closure
    print(name); // Use a variable declared in the parent function
  }
  name = 'Dart'; // reassign
  return displayName;
}
Copy the code

The resulting output is Dart, and you can see that the inner function accesses the variables of the outer function in the same lexical context.

The return value

In Dart, all functions must return a value, and if they do not, null is automatically returned:

foo() {}

assert(foo() == null);
Copy the code

Process control

This part is like most languages, so I’ll just go through it briefly here.

if-else

if(hasHause && hasCar){
    marry();
}else if(isHandsome){
    date();
}else{
    pass();
}
Copy the code

cycle

All kinds of for:

var list = [1.2.3];

for(var i = 0; i ! = list.length; i++){}for(var i in list){}
Copy the code

While and loop interrupts (interrupts also work in for) :

  var i = 0;
  while(i ! = list.length){if(i % 2= =0) {continue;
    }
     print(list[i]);
  }

  i = 0;
  do{
    print(list[i]);
    if(i == 5) {break; }}while(i ! = list.length);Copy the code

If the object is of type Iterable, you can also do something like a Java lambada:

list.forEach((i) => print(i));
  
list.where((i) =>i % 2= =0).forEach((i) => print(i));
Copy the code

switch

Switch can be used with types such as int, double, String, and enum. Switch can only be compared with objects of the same type.

var color = ' ';
  switch(color){
    case "RED":
      break;
    case "BLUE":
      break;
    default:}Copy the code

assert

In Dart, the assert statement is often used to check parameters. Its full expression is assert(condition, optionalMessage). If condition is false, an [AssertionError] exception will be raised to stop executing the program.

assert(text ! =null);

assert(urlString.startsWith('https'), 'URL ($urlString) should start with "https".');
Copy the code

Assert is usually only used in the development phase and is often ignored in the production runtime environment. Assert is turned on in the following scenario:

  1. The Flutterdebug mode.
  2. Some development tools likedartdevcIt is enabled by default.
  3. Some tools, likedartdart2js, can be through the parameters--enable-assertsOpen it.

Exception handling

Dart’s exception handling is similar to Java’s, but all exceptions in Dart are unchecked, which means you’re not forced to handle exceptions as you are in Java.

Dart provides both Exception and Error types of exceptions. In general, you should not catch errors of the Error type, but rather try to avoid them.

For example, OutOfMemoryError, StackOverflowError, and NoSuchMethodError are all errors of the Error type.

Mentioned above, because the Dart is not like Java can declare compile-time exception, this approach can make the code more concise, but easy to ignore the exception handling, so we at the time of coding, there may be exceptions in place should pay attention to read the API documentation, in addition to write their own way, if there is exception is thrown, to make a statement in the comments. For example, one of the methods in the File class is commented:

  /** * Synchronously readthe entire file contents as alist of bytes. * * Throwsa [FileSystemException] if theoperation fails. */
  Uint8List readAsBytesSync();
Copy the code

An exception is thrown

throw FormatException('Expected at least 1 section');
Copy the code

In addition to throwing exception objects, throw can throw objects of any type, but it is recommended to use standard exception classes as a best practice.

throw 'Out of llamas! ';
Copy the code

Catch exceptions

You can specify the exception type with the ON keyword:

 var file = File("1.txt");
  try{
    file.readAsStringSync();
  } on FileSystemException {
     //do something
  }
Copy the code

Get the exception object using the catch keyword, which takes two parameters, the first being the exception object and the second the error stack.

try{
    file.readAsStringSync();
} on FileSystemException catch (e){
    print('exception: $e');
} catch(e, s){ // Other types
   print('Exception details:\n $e');
   print('Stack trace:\n $s');
}
Copy the code

Throw to the upper level using rethrow:

 try{
    file.readAsStringSync();
  } on FileSystemException catch (e){
    print('exception: $e');
  } catch(e){
     rethrow;
  }
Copy the code

finally

Finally is used for operations such as releasing resources. It means that it must be executed eventually, even if a try… A catch has a return, and the code inside it promises to execute.

try{
     print('hello');
     return;
  } catch(e){
     rethrow;
  } finally{
     print('finally');
}
Copy the code

Output:

hello
finally
Copy the code

class

Dart is an object-oriented programming language. All objects are instances of a class that extends from the Object class.

A simple class:

class Point {
  num x, y;

  / / the constructor
  Point(this.x, this.y);
  
  // Instance method
  num distanceTo(Point other) {
    var dx = x - other.x;
    var dy = y - other.y;
    returnsqrt(dx * dx + dy * dy); }}Copy the code

Members of the class

The Dart through. To call class member variables and methods.

// Create an object, the new keyword can be omitted
var p = Point(2.2);

// Set the value of the instance variable y.
p.y = 3;

// Get the value of y.
assert(p.y == 3);

// Invoke distanceTo() on p.
num distance = p.distanceTo(Point(4.4));
Copy the code

You can also pass…? To avoid null objects. One of the criticisms of Java is that a lot of nullPonterExceptions are often needed to avoid nullPonterExceptions. In Dart, this problem can be easily avoided:

// If p is non-null, set its y value to 4.p? .y =4;
Copy the code

Dart does not use the keywords private, protected, or public. If you want to declare a variable private, you add an underscore underscore (_) before the variable name. The declared variable is private and visible only in the library.

class Point{
  num _x;
  num _y;
}
Copy the code

Constructor

If no constructor is declared, Dart generates a default constructor with no arguments for the class, declaring a constructor with arguments, as Java does:

class Person{
  String name;
  int sex;
  
  Person(String name, int sex){
    this.name = name;
    this.sex = sex; }}Copy the code

You can also use the simplified version:

Person(this.name, this.sex);
Copy the code

Or named constructor:

Person.badGirl(){
    this.name = 'Bad Girl';
    this.sex = 1;
}
Copy the code

You can also create instances with the factory keyword:

Person.goodGirl(){
	this.name = 'good Girl';
	this.sex = 1;
}

factory Person(int type){
	return type == 1 ? Person.badGirl(): Person.goodGirl();
}
Copy the code

Factory corresponds to the language-level implementation of the factory pattern in Design pattern and has a number of applications in Flutter’s library, such as Map:

// Some code
abstract class Map<K.V> {  
	factory Map.from(Map other) = LinkedHashMap<K, V>.from;
}
Copy the code

If the creation of an object is complex, such as choosing a different subclass to implement or caching instances, you can use this method. In the Map example above, we subclass LinkedHashMap by declaring factory (linkedhashmap. from is also a factory, which contains the creation process).

If you want to do something before the object is created, such as checking parameters, you can use the following methods:

 Person(this.name, this.sex): assert(sex == 1)
Copy the code

Some simple operations added after the constructor are called the Initializer List.

In Dart, the initialization sequence is as follows:

  1. Initializer list;
  2. Constructor that executes the parent class;
  3. Constructor to execute a subclass.
class Person{
  String name;
  int sex;

  Person(this.sex): name = 'a'.assert(sex == 1) {this.name = 'b';
    print('Person'); }}class Man extends Person{
   Man(): super(1) {this.name = 'c';
     print('Man'); }}void main(){
  Person person = Man();
  print('name : ${person.name}');
}
Copy the code

The output of the code above is:

Person
Man
name : c
Copy the code

If the subclass constructor does not explicitly call the parent constructor, the parent’s default no-argument constructor is called by default. Explicitly calling the parent class’s constructor:

Man(height): this.height = height, super(1);
Copy the code

Redirect constructor:

Man(this.height, this.age): assert(height > 0), assert(age > 0);

Man.old(): this(12.60); // Call the constructor above
Copy the code

Getter and Setter

In Dart, there are specific optimizations for Getter and Setter methods. Even if undeclared, each class variable has a get method by default, as shown in the implicit interface section.

class Rectangle {
  num left, top, width, height;

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

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

void main() {
  var rect = Rectangle(3.4.20.15);
  assert(rect.left == 3);
  rect.right = 12;
  assert(rect.left == - 8 -);
}
Copy the code

An abstract class

Dart’s abstract classes are similar to Java’s, except that they cannot be instantiated and can declare abstract methods.

abstract class AbstractContainer {
  num _width;

  void updateChildren(); // An abstract method that is enforced by inheriting subclasses.

  get width => this._width;
  
  int sqrt(){
    return_width * _width; }}Copy the code

Implied interface

Each class in Dart implicitly defines an interface that contains all of the class’s member variables and methods. You can re-implement the associated interface methods using the implements keyword:

class Person {
  // The get method is implied
  final _name;

  Person(this._name);

  String greet(String who) => 'Hello, $who. I am $_name.';
}

class Impostor implements Person {
  // Need to be reimplemented
  get _name => ' ';

  // Need to be reimplemented
  String greet(String who) => 'Hi $who. Do you know who I am? ';
}
Copy the code

Implement multiple interfaces:

class Point implements Comparable.Location {... }Copy the code

inheritance

Similar to Java, inheritance uses the extends keyword:

class Television {
  voidturnOn() { doSomthing(); }}class SmartTelevision extends Television {

  @override
  void turnOn() {
    super.turnOn(); // Call the parent methoddoMore(); }}Copy the code

Overloaded operator

In particular, Dart also allows overloaded operators, such as the subscript access element supported by the List class, to define the associated interface:

 E operator[] (int index);
Copy the code

We further illustrate the overloaded operator with the following example:

class MyList{

  var list = [1.2.3];

  operator[] (int index){
    returnlist[index]; }}void main() {
  var list = MyList();
  print(list[1]); 2 / / output
}
Copy the code

Extension methods

This feature is also one of the highlights of Dart (not supported until after Dart2.7) and can be tagged to Prototype in JavaScript. With this feature, you can even add new methods to the class library:

// Add a new method to the String class with the keyword extension
extension NumberParsing on String {
  int parseInt() {
    return int.parse(this); }}Copy the code

The following String can call this method:

print(The '42'.parseInt()); 
Copy the code

Enumerated type

Enumeration types and keep them consistent with Java keywords:

enum Color { red, green, blue }
Copy the code

Use in switch:

// color is the enmu color type
switch(color){
    case Color.red:
      break;
    case Color.blue:
      break;
    case Color.green:
      break;
    default:
      break;
}
Copy the code

The enumerated type also has a getter for index, which is a contiguous sequence of numbers starting at 0:

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

New feature: Mixins

This feature further enhances the ability to reuse code. If you’ve ever written Android layout XML code or Freemaker templates, this feature can be interpreted as inlclude.

Declare a mixin class:

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'); }}}Copy the code

Reuse with the with keyword:

class Musician extends Performer with Musical {
  / /...
}

class Maestro extends Person
    with Musical.Aggressive.Demented {
  Maestro(String maestroName) {
    name = maestroName;
    canConduct = true; }}Copy the code

Mixin classes can even implement inherited functionality via the ON keyword:

mixin MusicalPerformer on Musician {
  / /...
}
Copy the code

Class variables and class methods

class Queue {
  / / class variables
  static int maxLength = 1000;
  / / a class constant
  static const initialCapacity = 16;
  / / class methods
  static void modifyMax(intmax){ _maxLength = max; }}void main() {
  print(Queue.initialCapacity);
  Queue.modifyMax(2);
  print(Queue._maxLength);
}
Copy the code

The generic

There are two main functions of generics in object-oriented languages:

Type safety checks to kill errors at compile time:

var names = List<String> (); names.addAll(['Seth'.'Kathy'.'Lars']);
// Error compiling
names.add(42); 
Copy the code

2, enhance code reuse, such as the following code:

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}
Copy the code

You can combine them into a single class by generics:

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}
Copy the code

In Java, generics are implemented by type erasing, but in Dart they are real generics:

 var names = <String> []; names.addAll(['Tom'."Cat"]);
 // is can be used for type determination
 print(names is List<String>); // true
 print(names is List); // true
 print(names is List<int>); //false
Copy the code

You can restrict generic types with extends keyword, just like in Java:

abstract class Animal{}
class Cat extends Animal{}
class Ext<T extends Animal>{
  T data;
}

void main() {
  var e = Ext(); // ok
  var e1 = Ext<Animal>(); // ok
  var e2 = Ext<Cat>(); // ok
  var e3 = Ext<int> ();// compile error
}
Copy the code

Use the class library

All living programming languages have a powerful class library behind them that allows us to stand on the shoulders of giants without having to reinvent the wheel.

The import library

In Dart, the class library is imported by importing keywords.

The built-in class library uses dart: to introduce:

import 'dart:io';
Copy the code

Learn more about the built-in libraries here.

Third-party libraries or native DART files start with package: :

For example, import dio library for network request:

import 'package:dio/dio.dart';
Copy the code

The Dart application itself is a library, for example, my application name is CCsys, importing classes from other folders:

import 'package:ccsys/common/net_utils.dart';
import 'package:ccsys/model/user.dart';
Copy the code

If you use an IDE for development, you usually don’t have to worry about this, it will automatically import for you.

Dart manages libraries through pub.dev, similar to Maven in the Java world or Node.js NPM, where you can find many useful libraries.

Resolve class name conflicts

If the imported libraries have class name conflicts, you can avoid this problem by using aliases as:

import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;

// Use Element from lib1
Element element1 = Element(a);// Use Element from lib2
lib2.Element element2 = lib2.Element(a);Copy the code

Import partial classes

There may be many classes in a DART file, and if you want to reference only a few of them, you can add show or hide to handle this:

// File: my_lib.dart
class One {}

class Two{}

class Three{}
Copy the code

Use show to import classes One and Two:

// File: test.dart
import 'my_lib.dart' show One, Two;

void main() {
  var one = One();
  var two = Two();
  //compile error
  var three = Three();
}
Copy the code

We can also use hide to exclude Three.

// File: test.dart
import 'my_lib.dart' hide Three;

void main() {
  var one = One();
  var two = Two();
}
Copy the code

Lazy-loaded library

Lazy loading is currently only supported in the Web App (Dart 2JS). Flutter and Dart VM are not supported. We will give a brief introduction here.

You need to declare the lazy loading class library with deferred AS:

import 'package:greetings/hello.dart' deferred as hello;
Copy the code

When you need to use it, load it with loadLibrary() :

Future greet() async {
  await hello.loadLibrary();
  hello.printGreeting();
}
Copy the code

You can call loadLibrary multiple times and it will not be loaded twice.

Asynchronous support

This is a slightly more complicated topic, and we’ll cover it in a separate article. Keep an eye out for the next one.

The resources

  1. Top 10 reasons to learn Dart

  2. A tour of the Dart language

  3. An understanding of the Dart constant constructor

  4. JavaScript closures

aboutAgileStudio

We are a team of experienced independent developers and designers with solid technical strength and years of product design and development experience, providing reliable software customization services.