Flutter实现ControlExecutor进行多个异步任务执行时监听状态并可指定最后执行的异步并在指定的异步执行完毕后结束executor并回调。

1.场景

当有多个接口请求时,且接口调用不是同时进行时,而且接口调用有可能时链式的,中间也有可能加入别的逻辑,但是需要在第一个接口调用时打开等待框,在最后一个接口调用完成时关闭等待框类似需求时,可以用到ControlExecutor进行接口执行过程的监听,并可标记最后一个执行的接口,且会等待做了标记的接口完成执行后,关闭执行,并执行onFinish回调。

2.代码

其中executor.dart、group_key.dart、minitor.dart、ke_ex.dart跟上一篇文章CombineExecutor中的一样,请去上一篇文章中去拷贝。

control_executor.dart

Dart 复制代码
import 'package:kq_flutter_widgets/utils/ex/kq_ex.dart';

import 'core/executor.dart';
import 'core/group_key.dart';
import 'core/monitor.dart';

///可控制执行结束时机的执行者。
///主要用于多个接口联级调用或者链式调用等场景Loading框的控制。
///跟CombineExecutor原理类似,只是ControlExecutor可控制,
///不会自动自行完毕,需要用户主动调用stop或者给需要执行完毕的接口添加stop标记。
///可以监听多个接口联级调用、链式调用、多接混合调用出现异常和报错等监听,
///不干涉接口请求逻辑,只监听接口请求的
///成功状态(response.code == ApiResponse.success),失败状态(response.code != ApiResponse.success),
///接口catch后的监听,以及onError监听,例如在调用一系列接口时,
///调用第一个接口之前会回调onStart,
///等调用到接口状态设置了stop=true时的接口时和中间任意一个接口接口异常或失败状态时,
///则会回调onFinish,结束本次执行。
class ControlExecutor {
  ///执行的对象保存
  final Map<GroupKey, List<Monitor>> _monitors = {};

  ///Executor 保存
  final List<Executor> _executors = [];

  final Function(GroupKey key)? onStart;
  final Function(GroupKey key)? onFinish;

  ControlExecutor({this.onStart, this.onFinish});

  ///这里的逻辑跟CombineExecutor不同。
  _executor(GroupKey key) {
    Executor executor = Executor(key);
    if (!_executors.contains(executor)) {
      _executors.add(executor);
      onStart?.call(key);

      executor.start(callback: (key) {
        List<Monitor> combines = _get(key);
        bool flag = false;
        for (Monitor monitor in combines) {
          if (monitor.isError() ||
              monitor.isFinish() && (monitor.getExtra() ?? false)) {
            flag = true;
            break;
          }
        }

        //表示最后一个都已执行完成
        if (flag) {
          executor.stop(callback: (key) {
            onFinish?.call(key);
            _clear(key);
            _executors.remove(executor);
          });
        }
      });
    }
  }

  ///停止,在退出界面时调用
  stop() {
    for (Executor executor in _executors) {
      executor.stop();
    }
    _executors.clear();
    _clearAll();
  }

  ///获取合并执行观察者,
  ///设置到请求逻辑中。
  ///[stop] 是否停止。
  Monitor getMonitor(GroupKey key, {bool? stop}) {
    Monitor monitor = Monitor(extra: stop);
    _addCombine(key, monitor);
    _executor(key);
    return monitor;
  }

  ///新增一个monitor
  _addCombine(GroupKey key, Monitor combine) {
    if (key.isMonitor) {
      if (_monitors.containsKey(key)) {
        List<Monitor>? combines = _monitors[key];
        combines ??= [];
        if (!combines.contains(combine)) {
          combines.add(combine);
        }
      } else {
        _monitors.putIfAbsent(key, () => [combine]);
      }
    }
  }

  List<Monitor> _get(GroupKey key) {
    if (_isEmpty(key)) {
      return [];
    } else {
      return _monitors[key]!;
    }
  }

  ///monitor是否为空
  _isEmpty(GroupKey key) {
    return !_monitors.containsKey(key) || _monitors[key].isNullOrEmpty;
  }

  _clear(GroupKey key) {
    _monitors.remove(key);
  }

  ///清除全部的monitor
  _clearAll() {
    _monitors.clear();
  }
}

///测试
class ControlExecutorTest {
  test() {
    ///创建一个GroupKey,改key可用于一组需要调用的接口上
    GroupKey groupKey = GroupKey();

    ///创建对象
    ControlExecutor executor = ControlExecutor(
      onStart: (key) {
        ///print("开始执行");
      },
      onFinish: (key) {
        if (key == groupKey) {
          ///print("结束执行");
        }
      },
    );

    ///获取monitor 传入到接口调用中
    Monitor monitor1 = executor.getMonitor(groupKey);
    ///获取monitor 传入到接口调用中
    Monitor monitor2 = executor.getMonitor(groupKey);
    ///获取monitor 传入到接口调用中,结束的monitor
    Monitor monitor3 = executor.getMonitor(groupKey, stop: true);

    ///模拟异步对Monitor进行操作
    Future.delayed(const Duration(seconds: 2), () {
      monitor1.onFinish();
    });
    Future.delayed(const Duration(seconds: 3), () {
      monitor2.onFinish();
    });
    Future.delayed(const Duration(seconds: 5), () {
      monitor3.onFinish();
    });

    ///退出界面
    executor.stop();
  }
}

3.使用

相关推荐
LawrenceLan10 小时前
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
开发语言·flutter·dart
一豆羹11 小时前
macOS 环境下 ADB 无线调试连接失败、Protocol Fault 及端口占用的深度排查
flutter
行者9611 小时前
OpenHarmony上Flutter粒子效果组件的深度适配与实践
flutter·交互·harmonyos·鸿蒙
行者9614 小时前
Flutter与OpenHarmony深度集成:数据导出组件的实战优化与性能提升
flutter·harmonyos·鸿蒙
小雨下雨的雨14 小时前
Flutter 框架跨平台鸿蒙开发 —— Row & Column 布局之轴线控制艺术
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨14 小时前
Flutter 框架跨平台鸿蒙开发 —— Center 控件之完美居中之道
flutter·ui·华为·harmonyos·鸿蒙
小雨下雨的雨15 小时前
Flutter 框架跨平台鸿蒙开发 —— Icon 控件之图标交互美学
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨15 小时前
Flutter 框架跨平台鸿蒙开发 —— Placeholder 控件之布局雏形美学
flutter·ui·华为·harmonyos·鸿蒙系统
行者9616 小时前
OpenHarmony Flutter弹出菜单组件深度实践:从基础到高级的完整指南
flutter·harmonyos·鸿蒙
前端不太难16 小时前
Flutter / RN / iOS,在长期维护下的性能差异本质
flutter·ios