1. Dart event cycle model

  • Microtask queue Microtask queue
  • Event queue

The “microtask” is preferentially executed, and the “event queue” is executed only when there is no one. The “event queue” is executed once each time, and the “microtask” is less. IO, timer, click, and drawing belong to the events

2. Task scheduling

2.1 MicroTask queue

void main() {
  print("main start");
  scheduleMicrotask(() => print('microtask'));
  print("main end");
}

flutter: main start
flutter: main end
flutter: microtask
Copy the code

2.2 the Event queue

void main() {
  print("main start");
  Future(() => print('microtask'));
  print("main end");
}

flutter: main start
flutter: main end
flutter: microtask
Copy the code

3 the Future with FutureBuilder

3.1 the Future use

Future() Future.microtask() Future.sync() Future.value() Future.delayed() Future.error() Future.sync()

void main() {
  print("main start");
  
  // Delay execution
  Future.delayed(Duration(seconds: 1), () = >print('Future running in Event Queue in 1 second'));
  
  // Execute the command immediately
  Future.sync(() = >print('Synchronous running Future')).whenComplete(() => print('complete'));
  
  // execute asynchronously, then execute sequentially after executing asynchronous methods,
  // The catchError method will be executed if an error occurs
  // whenComplete is eventually executed with or without errors
  Future(() => print('task'))
      .then((_) => print('callback1'))
      .then((_) => print('callback2'))
      .catchError((error) => print("$error"))
      .whenComplete(() => print('complete'));

  print("main end");
}

// Result outputCreate a Microtask Queue with a Future flutter: complete flutter: task flutter: callback1 flutter: callback2 flutter: complete flutter:1The Future running in the Event Queue seconds laterCopy the code

3.2 the Future. Wait

Wait for multiple tasks to complete a callback

void main() {
  print("main start");

  Future.wait([
    Future.delayed(Duration(seconds: 2), () = >"Hello"),
    Future.delayed(Duration(seconds: 4), () = >"Flutter")
  ]).then((results) {
    print("${results[0]} + ${results[1]}");
  }).catchError((e) => print(e));

  print("main end");
}
  
/ / output
flutter: main start
flutter: main end
flutter: Hello + Flutter
  
Copy the code

3.3 Completer

The biggest difference with Future is manual control of completion timing

  /// Completer
  var completer = Completer();
  // Completer contains a future
  var future = completer.future;
  // Set the future callback after execution
  future.then((value) => print("then $value"));
  
  print('do something else');
  
  // You can control the completion time and then execute the then callback
  completer.complete("done");

  print("main end");
}

/ / output
flutter: main start
flutter: do something else
flutter: main end
flutter: then done
Copy the code

3.4 FutureBuilder

Usage scenario: Rely on asynchronous data to dynamically update the UI. FutureBuilder dynamically builds itself based on the dependent future

FutureBuilder({
  this.future,   // Dependent future, usually an asynchronous time-consuming task
  this.initialData,  // Initial data, the default data set by the user
  @required this.builder,  // Widget builder, which is called multiple times at different stages of Future execution
})

// Build a builder
Function (BuildContext context, AsyncSnapshot snapshot)
// Snapshot contains the status and result information of the current asynchronous task.
// For example, you can obtain the asynchronous task status through snapshot.connectionState
// snapshot.hasError Checks whether an error occurs in the asynchronous task
Copy the code

FutureBuilder use

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page')); }}class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  Future<String> mockNetworkData() async {
    return Future.delayed(Duration(seconds: 2), () = >throw);
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: FutureBuilder<String>(
          future: mockNetworkData(),
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if(snapshot.connectionState == ConnectionState.done) {
              if(snapshot.hasError) {
                // The request failed
                return Text("Error: ${snapshot.error}");
              } else {
                // Request completed
                return Text("Contents: ${snapshot.data}"); }}else {
              / / display loading
              returnCircularProgressIndicator(); }})),); }Copy the code

4 async/await

The methods declared by ASNC have the following meanings

  • Method returns a Future
  • Await can only occur in async
  • The method executes the code in the method synchronously until it encounters the first await, waits for the await to complete before executing the code below, but the method returns at the first await,
  • As soon as the Future task referenced by await completes, the next line of code from await executes immediately
  • Async can have multiple await functions and return a Future with each await, similar to the then string callback
  • Async functions can return a Future without await
void main() {
  fool();
}

fool() async {
  print('foo E');
  String v = await bar();
  print('foo X $v');
}

bar() async {
  print('bar E');
  return 'hello';
}

/ / output
flutter: foo E
flutter: bar E
flutter: foo X hello
Copy the code

fool() async {
  print('foo E');
  return Future.sync(bar).then((v) => print('foo X $v'));
}
Copy the code

5 the Stream and StreamBuilder

A Stream is also used to receive asynchronous data, and unlike a Future can receive multiple asynchronous returns. Data transfer or error exceptions can be triggered by multiple successes or failures. Application scenarios include asynchronous tasks that read data for multiple times, network content downloading, and file reading

5.1 Steam use

void main() {
  print('main start');

  Stream.fromFutures([
    // Return the result after 1 second
    Future.delayed(new Duration(seconds: 1), () {
      return "hello 1";
    }),
    // Throw an exception
    Future.delayed(new Duration(seconds: 2), () {
      throw AssertionError("Error");
    }),
    // The result is returned after 3 seconds
    Future.delayed(new Duration(seconds: 3), () {
      return "hello 3";
    })
  ]).listen((data) => print(data), onError: (e) => print(e),
      onDone: () => print("Done"));

  print('main end');
}

/ / output
flutter: main start
flutter: main end
flutter: hello 1
flutter: Assertion failed
flutter: hello 3
flutter: Done
Copy the code

5.2 StreamBuilder use

StreamBuilder UI component StreamBuilder constructor used in conjunction with a Stream to display changes in events (data) on a Stream

StreamBuilder({
  Key key,
  this.initialData,
  Stream<T> stream,
  @required this.builder,
})
Copy the code

StreamBuilder use

class _MyHomePageState extends State<MyHomePage> {

  Stream<int> counter() {
    return Stream.periodic(Duration(seconds: 100), (i) => i);
  }

  @override
  void initState() {

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: buildStream(context)
      ),
    );
  }

  Widget buildStream(BuildContext context) {
    return StreamBuilder<int>(
      stream: counter(),
      builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
        if (snapshot.hasError)
          return Text('Error: ${snapshot.error}');
        switch (snapshot.connectionState) {
          case ConnectionState.none:
            return Text('no Stream');
          case ConnectionState.waiting:
            return Text('Waiting for data... ');
          case ConnectionState.active:
            return Text('active: ${snapshot.data}');
          case ConnectionState.done:
            return Text('Stream closed ');
        }
        return null; // unreachable}); }}Copy the code