Flutter 异步编程 Future、FutureBuilder,await 与 async

文章目录

    • Future 是什么?
      • 基本用法
        • Future.value(value)
        • Future.error()
        • Future.delayed()
        • Future.then()
        • Future.catchError()
        • Future.whenComplete()
    • FutureBuilder
    • await 与 async
    • 参考

Future 是什么?

在之前的文章中,我们已经使用了Future。如文件操作、SharedPreferences都会返回一个Future。【Flutter 本地数据存储(文件、SharedPreferences 、数据库 sqlite)使用示例】。

dart api文档中对Future的描述是表示延迟计算的对象。

在文件操作中使用Future是因为文件读取是耗时操作,不能马上返回结果,通过Future延迟之后,我们可以在回调中获取到文件读取之后的结果。

Future的回调返回有两种方式,带有值(futuresuccess)返回或错误(futuresfuture)返回。

我们可以把Future想象为一个装有数据的盒子,在一段时间后打开。盒子打开之后,里面有可能有我们想要的东西 value,也有可能不是我们想要的东西error

所以future就存在三个状态:

  • 盒子未打开状态(构造阶段)
  • 盒子打开里面有我们想要的 value(成功返回)
  • 盒子打开但是里面不是我们想要的 value(失败返回)

下面根据这三种状态来介绍Future的使用

基本用法

Flutter中很多方法会直接返回Future对象,例如:

final myFuture = SharedPreferences.getInstance();

有时候我们也会通过构造函数直接new Future来获取Future实例。

 final myFuture = Future();

Future.value(value)

创建已知valueFuture。当您构建使用缓存的服务时,此构造函数很有用。

使用示例如下:

final myFuture = Future.value(12);

Future.error()

创建已知errorFuture。和Future.value()类似

使用示例如下:

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

Future.delayed()

创建一个延迟执行的Future。在 Flutter 使用 dio 库实现网络请求及 Json 数据解析示例 中我们对 dio 进行了二次封装,在showLoading的时候想显示弹窗,但是这时候showDialog中的context还没获取到,所以我们需要延迟之后才显示弹窗。

使用示例如下:

Future.delayed(Duration(milliseconds: 200)).then((e) {
  // 延迟之后的操作
});

以上的返回结果都是Future,也就是完成了Future的第一个状态,构建。
接着通过then()就可以获取到我们真正需要的值或者通过catchError()来捕获错误信息。

Future.then()

处理正确的返回结果。只有单个参数,并且then返回的还是Future对象,因此可以一直链式调用then方法

该方法返回泛型的onValue数据,以及可选命名函数onErroronError回调必须接受一个或两个参数,如果onError接受两个参数,则同时使用错误和堆栈跟踪进行调用,否则仅使用错误对象进行调用。

Future then(FutureOr onValue(T value), {Function onError});

示例:
在这里插入图片描述

Future.delayed(Duration(seconds: 1)).then((value) {
  print("第一个 then");
}).then((value) {
  print("第二个 then");
});

如果我们在执行的时候遇到了error可以通过catchError来捕捉错误信息,当有错误时就不走then回调,直接走catchError回调。

Future.catchError()

它的工作原理与then()相同,除了它接受一个error而不是一个value,且会返回一个errorFuture

该方法返回onError回调,以及可选命名函数test,以在调用回调之前检查错误。

Future catchError(Function onError, {bool test(Object error)});

示例:
在这里插入图片描述

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

Future还提供了类似于try-catch-finally中的finally块,whenComplete()方法

Future.whenComplete()

不够执行成功或者失败都会执行whenComplete()方法,并返回一个Future。类似于try-catch-finally中的finally块。

示例:
在这里插入图片描述

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

Flutter还提供了FutureBuilder widget用于异步动态更新UI

FutureBuilder

基于与Future交互的widget,并根据snapshots中的状态用不同widget去构建。

既然是个widget,我们看一下构造函数:

  const FutureBuilder({
    Key key,
    this.future,// Future 对象
    this.initialData,// 初始化的数据,在 Future 对象创建完成之前给 snapshots 提供数据
    @required this.builder,// 构建器提供了一个 AsyncSnapshot 对象,该对象的 AsyncSnapshot.connectionState 属性有:none(Future 为null),waiting(Future 为等待状态),done(Future 为结束状态)
  })

示例:
Flutter 异步编程 Future、FutureBuilder,await 与 async_第1张图片
以上效果源码可查看 FutureBuilder源码(async.dart文件)504-562行。

await 与 async

在使用Future的时候,如果有太多异步任务,那么代码的嵌套层级将会很深。dart中提供了和JavaScript中一样的方式来解决异步代码层级过深问题,那就是通过async 和 await关键字。

async 和 await关键字提供了一种声明性的方式来定义异步函数并使用其结果。
使用asyncawait时,请记住以下两个基本准则:

  • 要定义异步函数,请在函数主体之前添加async
  • await关键字仅在异步函数中起作用

文档 中的同步异步对比例子:
Flutter 异步编程 Future、FutureBuilder,await 与 async_第2张图片
主要区别有以上三点

  • 异步函数主体前增加了 async 关键字
  • 异步函数使用 await 关键字接收值
  • 在使用async关键字时需要将返回值转为用Future<原返回值类型>

参考

  • YouTube-Flutter 异步编程之 Future
  • Dart asynchronous programming: Futures
  • Future class
  • YouTube-Flutter 异步编程之 async & await
  • Asynchronous programming: futures, async, await

你可能感兴趣的:(Flutter,笔记)