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

news/2024/7/2 23:27:16

1.场景

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

2.代码

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

control_executor.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.使用


http://lihuaxi.xjx100.cn/news/1518651.html

相关文章

图像识别技术在智能交通领域的革命

导言&#xff1a; 智能交通领域一直以来都面临着交通安全和效率的挑战&#xff0c;而图像识别技术的快速发展正为这一领域带来了革命性的变革。本文将深入探讨图像识别技术在智能交通领域的应用&#xff0c;以及它所带来的潜在影响。 一、图像识别技术在智能交通中的应用 车辆…

电脑安装 MIUI+

windows电脑&#xff0c;打开命令框&#xff0c;输入下面命令 winget install Xiaomi.MIUI 如果是小米笔记本&#xff0c;还可以通过 小米帮助中心-小米商城 (mi.com) 进行下载安装

protobuf安装及简单使用

protobuf简单介绍和ubuntu 16.04环境下安装教程&#xff1a;https://pythonjishu.com/rgdzjkxgoyicrhu/ Protocol Buffers使用指南&#xff1a;https://blog.csdn.net/jarvanxy/article/details/132256759

汽车信息安全导图

尊敬的读者们,欢迎来到我的信息安全专栏。在这个专栏中,我将结合我在信息安全领域的开发经验,为大家深入浅出地讲解信息安全的重要性和相关知识点。 在数字化时代,信息成为了我们生活中不可或缺的一部分。我们的个人信息、交易数据、社交网络、公司机密等都以电子形式存储…

SAP 物料主数据屏幕增强

增强步骤 1.为主表添加一个附加结构 根据业务需求新建一个结构&#xff0c;结构中放入需要增强的屏幕字段并激活。 打开事务代码SE11&#xff0c;在需要保存的主表中添加这个附加结构并激活。 注&#xff1a;根据业务需求及屏幕增强的视图判断需要保存的主表是哪张&#xff…

Scrum敏捷开发企业实战培训

课程简介 Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架。 这是一个两天的实训课程&#xff0c;面向研发管理者、项目经理、产品经理、研发团队等&#xff0c;旨在帮助学员全面系统地学习Scrum和敏捷开发, 帮助企业快速启动敏…

【Python爬虫笔记】爬虫代理IP与访问控制

一、前言 在进行网络爬虫的开发过程中&#xff0c;有许多限制因素阻碍着爬虫程序的正常运行&#xff0c;其中最主要的一点就是反爬虫机制。为了防止爬虫程序在短时间内大量地请求同一个网站&#xff0c;网站管理者会使用一些方式进行限制。这时候&#xff0c;代理IP就是解决方…

Android AAPT: error: resource color 异常原因处理

异常体现&#xff1a; Android resource linking failed ERROR:E:\software\Developer\APP\GaoDeTest2\app\src\main\res\values\themes.xml:3:5-9:13: AAPT: error: resource color/purple_500 (aka com.example.gaodetest2:color/purple_500) not found.ERROR:E:\software\De…