likes
comments
collection
share

Flutter 之 Completer 源码解读以及应用

作者站长头像
站长
· 阅读数 38

[》跳过拾光记忆]

拾光记忆

简介: 该篇主要介绍15 篇文章含有功能的目录,可根据自己的需求选择对应的功能介绍查看。 推荐: ⭐️⭐️⭐️⭐️⭐️

简介: 该篇主要介绍 Flutter 之 IImage 库中如何实现图像反色功能以及实现原理的介绍。 推荐: ⭐️⭐️⭐️⭐️⭐️

简介: 该篇主要介绍 Flutter 之 图形(Canvas) 绘制路径 (Path)基础功能以及方法实现底层代码的解析。 推荐: ⭐️⭐️⭐️⭐️⭐️

简介: 该篇主要介绍 Flutter 中聊天气泡的实现和图像点九图以及在使用图像拉伸实现气泡时遇到问题的分析和解决方法的总结。 推荐: ⭐️⭐️⭐️⭐️⭐️

简介: 该篇主要介绍 YAML的基础信息以及基础语法和对应转化为 JSON 的实例举例。 推荐: ⭐️⭐️⭐️⭐️⭐️

简介: 该篇主要介绍 Dart 中关键字之一的 final,它的特点、应用时机、优点的总结以及应用实例验证和展示。 推荐: ⭐️⭐️⭐️⭐️

简介: 该篇主要介绍 FlutterYAML 文件的各种读取形式以及 YAML 数据的获取。 推荐: ⭐️⭐️⭐️⭐️

[返回拾光记忆《]

一、 简述

Flutter 中,Completer 是一个用于处理异步操作的类。它允许你创建一个 Future 对象,并且在某个时刻手动地完成该 Future,或者传递一个错误作为 Future 的结果。

二、用途

Completer 的主要用途之一是在需要手动控制异步操作的场景下。通过 Completer,你可以在任何时候手动完成 Future,而不是依赖于异步操作本身的完成。

例如,你可以创建一个 Completer 对象,将其关联的 Future 传递给某个异步操作,然后在异步操作完成时手动调用 complete 方法完成该 Future,或者在发生错误时调用 completeError 方法完成一个失败的 Future

Completer 还常与其他异步处理工具(如Future、Stream等)结合使用,以实现更复杂的异步操作。它提供了一种手动控制 Future 完成的灵活性和自定义性,使得在异步编程中处理复杂逻辑变得更加方便。

三、主要方法

Completer类提供了以下主要方法:

  1. Completer()Completer.sync(): 创建一个Completer对象。
  2. future: 返回与Completer关联的Future对象,可以使用该Future进行后续的操作。
  3. complete(value): 手动完成Future,并将指定的value作为结果进行传递。这将触发与Completer关联的Future的完成回调。
  4. completeError(error, [stackTrace]): 手动完成一个失败的Future,并将指定的error和可选的stackTrace作为结果进行传递。这将触发与Completer关联的Future的错误回调。
  5. isCompleted: 返回一个布尔值,指示Completer关联的Future是否已经完成。

四、应用

1. Completer 的基础应用

Completer基础实例应用如下:

void _incrementCounter() {
 completerDemo()
      .then((value) => log('返回数据:$value'))
      .whenComplete(() => log('请求完成'))
      .catchError((err) => log('请求失败:${err.toString()}'));
}

Future<int> completerDemo() {
  final Completer<int> completer = Completer();
  Future.delayed(const Duration(seconds: 5), () {
    final int value = Random().nextInt(10);
    if (value < 5) {
      completer.complete(value);
    } else {
      completer.completeError('失败');
    }
  });
  return completer.future;
}

上述代码分析: 在第 11 代码返回结果小于 5 时,则 Completer 调用 completer.complete(x) 方法返回数据,输出日志如下:

[log] 返回数据:4
[log] 请求完成

在第 11 代码返回结果大于等于 5 时,则 Completer 调用 completer.completeError(x) 方法返回错误数据,输出日志如下:

[log] 请求完成
[log] 请求失败:失败

从上述分析可知,无论 Completer 是成功还是失败,它返回的 Future 对象的 whenComplete() 方法都调用。

2. Completer 进阶应用

  1. 场景设定:小明要购买演唱会的门票,小明通过一个方法同时向北京郑州上海 三个城市查询演唱会余票,然后直接返回优先响应城市的门票。

  2. 预设:

    • 小明查询调用的方法是 Future<String> getCountOfTicket()
    • 查询城市余票的方法是 Future<int> findLastTicket()
  3. 解决方案 我们使用 Completer 来解决这个问题,解决代码如下:

    • 各城市获取余票代码

      Future<Map> findLastTicket(String value) {
        final int count = Random().nextInt(4) + 1;
        return Future.delayed(Duration(seconds: count), () {
          return {
            'count': count,
            'city': value,
          };
        });
      }
      

      上面使用 Future.delayed() 模拟查询的耗时。

    • 同时查询方法

      Future<String> getCountOfTicket() {
        final Completer<String> completer = Completer();
        findLastTicket('北京').then((value) {
          if (!completer.isCompleted) {
            completer.complete('${value['city']} - ${value['count']}');
          }
        });
        findLastTicket('上海').then((value) {
          if (!completer.isCompleted) {
            completer.complete('${value['city']} - ${value['count']}');
          }
        });
        findLastTicket('郑州').then((value) {
          if (!completer.isCompleted) {
            completer.complete('${value['city']} - ${value['count']}');
          }
        });
        return completer.future;
      }
      

      注意: 上述代码的中的 completer.isCompleted 的应用。

      isCompleted 是判断 Completer 是否完成, 默认值是 false,如果 Completer 已经调用过 complete() 或者 completeError() 方法之后 isCompleted 的值就变成 true, 如果你再次调用 complete() 或者 completeError() 会提示报错: StateError (Bad state: Future already completed),说是这个 Completer 已经完成。

    • 完整的解决代码

      // 小明购票的方法
      void _incrementCounter() {
        getCountOfTicket()
            .then((value) => log('返回数据:$value'))
            .whenComplete(() => log('请求完成'))
            .catchError((err) => log('请求失败:${err.toString()}'));
      }
      
      // 获取3个城市余票的方法
      Future<String> getCountOfTicket() {
        final Completer<String> completer = Completer();
        findLastTicket('北京').then((value) {
          if (!completer.isCompleted) {
            completer.complete('${value['city']} - ${value['count']}');
          }
        });
        findLastTicket('上海').then((value) {
          completer.complete('${value['city']} - ${value['count']}');
          if (!completer.isCompleted) {
            completer.complete('${value['city']} - ${value['count']}');
          }
        });
        findLastTicket('郑州').then((value) {
          if (!completer.isCompleted) {
            completer.complete('${value['city']} - ${value['count']}');
          }
        });
        return completer.future;
      }
      
      // 查询每个城市余票的方法
      Future<Map> findLastTicket(String value) {
        final int count = Random().nextInt(4) + 1;
        return Future.delayed(Duration(seconds: count), () {
          return {
            'count': count,
            'city': value,
          };
        });
      }
      

      上述代码运行的结果如下:

      [log] 返回数据:郑州 - 2
      [log] 请求完成
      

    总结:这就是 Completer 在同时进行多个请求,优先选择首选返回数据的请求的应用,注意 isCompleted 的使用。

3. Completer 的嵌套

Completer 的嵌套:

void _incrementCounter() {
  nestedMethod()
      .then((value) => log('返回数据:$value'))
      .whenComplete(() => log('请求完成'))
      .catchError((err) => log('请求失败:${err.toString()}'));
}

// MARK: -- 嵌套
Future<String> nestedMethod() {
  final Completer<int> countCompleter = Completer();
  final Completer<String> markCompleter = Completer();
  countCompleter.complete(10);
  countCompleter.future.then((value) => markCompleter.complete('票数:$value'));
  return markCompleter.future;
}

上述是 Completer 的嵌套简单使用,常用于等待上一个请求或者事件的结果来触发下一个请求或者事件。

4. Completer.sync() 详解

Completer.sync()Completer 类的一个构造器,它创建的 Completer 在完成时同步地通知它的监听器。这与默认的 Completer() 不同,后者在事件循环的下一个微任务中通知监听器。

这意味着如果你使用 Completer.sync(),那么当你调用 complete()completeError() 方法时,所有等待 Future 结果的 .then()、.catchError()、以及 .whenComplete() 的回调会立即执行,不需要等待事件循环的下一个微任务。

实例代码如下:

Future<int> syncCompleterMethod() {
  final Completer<int> syncCompleter = Completer.sync();
  log('sync: 1');
  syncCompleter.future.then((value) => log('sync: 2'));
  syncCompleter.complete(1);
  log('sync: 3');
  stopwatch.start();
  return syncCompleter.future;
}

上述代码运行输出如下:

[log] sync: 1
[log] sync: 2
[log] sync: 3

如果将是上述代码的第 2 行改为 final Completer<int> syncCompleter = Completer();,则输出结果如下:

[log] sync: 1
[log] sync: 3
[log] sync: 2

总结:这个方法我们开发几乎使用不到,使用它风险较高,所以一般不用。想将一个同步的结果转化为 Flutter, 可以直接使用 Future.value() 方法。

五、鼓励与支持

上面是 Flutter Completer 的详细介绍,我们可以根据自己的业务需求选择合适的方法来完成任务。如果你感觉总结的还可以,那请留下你的点赞、关注与分享,如果感觉哪里有不正确的或者建议,请评论或者留言。 本篇文章的测试代码地址 Completer 高级介绍Demo

转载自:https://juejin.cn/post/7282994349444628517
评论
请登录