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


    1.场景

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

    2.代码

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

    control_executor.dart

    1. import 'package:kq_flutter_widgets/utils/ex/kq_ex.dart';
    2. import 'core/executor.dart';
    3. import 'core/group_key.dart';
    4. import 'core/monitor.dart';
    5. ///可控制执行结束时机的执行者。
    6. ///主要用于多个接口联级调用或者链式调用等场景Loading框的控制。
    7. ///跟CombineExecutor原理类似,只是ControlExecutor可控制,
    8. ///不会自动自行完毕,需要用户主动调用stop或者给需要执行完毕的接口添加stop标记。
    9. ///可以监听多个接口联级调用、链式调用、多接混合调用出现异常和报错等监听,
    10. ///不干涉接口请求逻辑,只监听接口请求的
    11. ///成功状态(response.code == ApiResponse.success),失败状态(response.code != ApiResponse.success),
    12. ///接口catch后的监听,以及onError监听,例如在调用一系列接口时,
    13. ///调用第一个接口之前会回调onStart,
    14. ///等调用到接口状态设置了stop=true时的接口时和中间任意一个接口接口异常或失败状态时,
    15. ///则会回调onFinish,结束本次执行。
    16. class ControlExecutor {
    17. ///执行的对象保存
    18. final MapList> _monitors = {};
    19. ///Executor 保存
    20. final List _executors = [];
    21. final Function(GroupKey key)? onStart;
    22. final Function(GroupKey key)? onFinish;
    23. ControlExecutor({this.onStart, this.onFinish});
    24. ///这里的逻辑跟CombineExecutor不同。
    25. _executor(GroupKey key) {
    26. Executor executor = Executor(key);
    27. if (!_executors.contains(executor)) {
    28. _executors.add(executor);
    29. onStart?.call(key);
    30. executor.start(callback: (key) {
    31. List combines = _get(key);
    32. bool flag = false;
    33. for (Monitor monitor in combines) {
    34. if (monitor.isError() ||
    35. monitor.isFinish() && (monitor.getExtra() ?? false)) {
    36. flag = true;
    37. break;
    38. }
    39. }
    40. //表示最后一个都已执行完成
    41. if (flag) {
    42. executor.stop(callback: (key) {
    43. onFinish?.call(key);
    44. _clear(key);
    45. _executors.remove(executor);
    46. });
    47. }
    48. });
    49. }
    50. }
    51. ///停止,在退出界面时调用
    52. stop() {
    53. for (Executor executor in _executors) {
    54. executor.stop();
    55. }
    56. _executors.clear();
    57. _clearAll();
    58. }
    59. ///获取合并执行观察者,
    60. ///设置到请求逻辑中。
    61. ///[stop] 是否停止。
    62. Monitor getMonitor(GroupKey key, {bool? stop}) {
    63. Monitor monitor = Monitor(extra: stop);
    64. _addCombine(key, monitor);
    65. _executor(key);
    66. return monitor;
    67. }
    68. ///新增一个monitor
    69. _addCombine(GroupKey key, Monitor combine) {
    70. if (key.isMonitor) {
    71. if (_monitors.containsKey(key)) {
    72. List? combines = _monitors[key];
    73. combines ??= [];
    74. if (!combines.contains(combine)) {
    75. combines.add(combine);
    76. }
    77. } else {
    78. _monitors.putIfAbsent(key, () => [combine]);
    79. }
    80. }
    81. }
    82. List _get(GroupKey key) {
    83. if (_isEmpty(key)) {
    84. return [];
    85. } else {
    86. return _monitors[key]!;
    87. }
    88. }
    89. ///monitor是否为空
    90. _isEmpty(GroupKey key) {
    91. return !_monitors.containsKey(key) || _monitors[key].isNullOrEmpty;
    92. }
    93. _clear(GroupKey key) {
    94. _monitors.remove(key);
    95. }
    96. ///清除全部的monitor
    97. _clearAll() {
    98. _monitors.clear();
    99. }
    100. }
    101. ///测试
    102. class ControlExecutorTest {
    103. test() {
    104. ///创建一个GroupKey,改key可用于一组需要调用的接口上
    105. GroupKey groupKey = GroupKey();
    106. ///创建对象
    107. ControlExecutor executor = ControlExecutor(
    108. onStart: (key) {
    109. ///print("开始执行");
    110. },
    111. onFinish: (key) {
    112. if (key == groupKey) {
    113. ///print("结束执行");
    114. }
    115. },
    116. );
    117. ///获取monitor 传入到接口调用中
    118. Monitor monitor1 = executor.getMonitor(groupKey);
    119. ///获取monitor 传入到接口调用中
    120. Monitor monitor2 = executor.getMonitor(groupKey);
    121. ///获取monitor 传入到接口调用中,结束的monitor
    122. Monitor monitor3 = executor.getMonitor(groupKey, stop: true);
    123. ///模拟异步对Monitor进行操作
    124. Future.delayed(const Duration(seconds: 2), () {
    125. monitor1.onFinish();
    126. });
    127. Future.delayed(const Duration(seconds: 3), () {
    128. monitor2.onFinish();
    129. });
    130. Future.delayed(const Duration(seconds: 5), () {
    131. monitor3.onFinish();
    132. });
    133. ///退出界面
    134. executor.stop();
    135. }
    136. }

    3.使用

  • 相关阅读:
    【0-1系列】从0-1快速了解搜索引擎Scope以及如何快速安装使用(下)
    内中断(一)
    electron-builder允许安装时请求提升权限
    springcloud--Sentinel(服务容错)
    【.NET Core】深入理解IO之File类
    操作系统安全:Windows与Linux的安全标识符,身份鉴别和访问控制
    TS代码整洁之道(下)
    快手订单导出
    正向代理的反爬虫与防DDoS攻击:保护网站免受恶意行为
    linux驱动开发:中断和时间管理
  • 原文地址:https://blog.csdn.net/u012800952/article/details/132696168