• Flutter实现CombineExecutor进行多个异步分组监听,监听第一个异步执行的开始和最后一个异步执行结束时机。


    1.场景

    我们在调用接口时,很多时候会同时调用多个接口,接口都是异步执行,我们很难知道调用的多个接口哪个会最后执行完成,我们有时候需要对最后一个接口执行完成的时机监听,所以基于该需求,设计了CombineExecutor,对类似的需求进行监听。

    2.代码

    group_key.dart

    1. ///合并执行分类
    2. class GroupKey {
    3. ///是否需要监听,不需要监听,则不会执行监听回调
    4. final bool isMonitor;
    5. GroupKey({this.isMonitor = true});
    6. }

    executor.dart

    1. import 'group_key.dart';
    2. ///执行者
    3. ///开始一个无限循环的执行进程,等待事件默认50毫秒
    4. class Executor {
    5. final GroupKey key;
    6. ///延迟时间。
    7. ///进程执行的快慢,单位毫秒ms,时间越短,反应越灵敏,
    8. ///但是消耗的新能越多,不能设置为0,否则会卡住进程。
    9. ///默认延迟50ms。
    10. final int? delayed;
    11. bool _stop = true;
    12. Function(GroupKey key)? _stopCallback;
    13. Function(GroupKey key)? _startCallback;
    14. Executor(this.key, {this.delayed});
    15. ///开始执行[Executor]
    16. ///[callback]会循环调用
    17. start({Function(GroupKey key)? callback}) async {
    18. _stop = false;
    19. _startCallback = callback ?? _startCallback;
    20. while (!_stop) {
    21. _startCallback?.call(key);
    22. await Future.delayed(Duration(milliseconds: delayed ?? 50));
    23. }
    24. _stopCallback?.call(key);
    25. }
    26. ///结束执行[Executor]
    27. ///[callback]只会在进程结束时执行一次
    28. stop({Function(GroupKey key)? callback}) {
    29. _stop = true;
    30. _stopCallback = callback ?? _stopCallback;
    31. }
    32. ///是否已启动
    33. bool isStart() {
    34. return !_stop;
    35. }
    36. @override
    37. int get hashCode => key.hashCode;
    38. @override
    39. bool operator ==(Object other) =>
    40. other is! Executor ? false : key == other.key;
    41. }

    monitor.dart

    1. import 'package:kq_flutter_widgets/utils/str_util.dart';
    2. ///合并执行状态持有
    3. class Monitor {
    4. dynamic extra;
    5. bool _isStart = false;
    6. bool _isFinish = false;
    7. bool _isError = false;
    8. Monitor({this.extra});
    9. ///该方法接口开始调用时调用
    10. @Deprecated("只需要监听完成,不需要监听开始,创建即开始")
    11. onStart() {
    12. _isStart = true;
    13. }
    14. ///该方法接口调用完成时调用
    15. onFinish() {
    16. _isFinish = true;
    17. }
    18. ///该方法接口出错或者请求失败时调用
    19. onError() {
    20. _isError = true;
    21. }
    22. ///该接口是否已开始调用
    23. @Deprecated("只需要监听完成,不需要监听开始,创建即开始")
    24. bool isStart() {
    25. return _isStart;
    26. }
    27. ///该接口是否已完成调用
    28. bool isFinish() {
    29. return _isFinish;
    30. }
    31. ///该接口是否调用出错
    32. bool isError() {
    33. return _isError;
    34. }
    35. ///获取额外数据
    36. T? getExtra() {
    37. return StrUtil.getValue(extra);
    38. }
    39. ///重置,以便复用
    40. reset() {
    41. _isStart = false;
    42. _isFinish = false;
    43. _isError = false;
    44. }
    45. }

    str_util.dart

    1. /// 字符串辅助类
    2. class StrUtil {
    3. ///类型判断
    4. static T? getValue(var value) {
    5. if (value == null) {
    6. return null;
    7. } else if (T == bool) {
    8. return (value == "1" || value == "true" || value is bool) as T;
    9. } else if (T == String) {
    10. return value as T;
    11. } else if (T == int) {
    12. return int.parse(value) as T;
    13. } else if (T == double) {
    14. return double.parse(value) as T;
    15. } else {
    16. return value;
    17. }
    18. }
    19. }

    combine_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. ///只监测接口执行过程,不涉及接口回调参数等处理。
    7. ///以最开始执行的接口开始回调[onStart]方法,
    8. ///以最后执行完成的接口回调[onFinish]方法。
    9. ///当第一个回调开始了,并已回调完成了,表示整个接口执行完毕,
    10. ///当第一个接口执行完毕后,还没开始执行第二个接口,则即使他们有共同的[GroupKey],
    11. ///他们也不能在一个处理周期中处理,我们把一个同一个[GroupKey]下执行的[onStart]和[onFinish],
    12. ///表示一个处理周期。
    13. class CombineExecutor {
    14. ///执行的对象保存
    15. final MapList> _combines = {};
    16. ///Executor 保存
    17. final List _executors = [];
    18. final Function(GroupKey key)? onStart;
    19. final Function(GroupKey key)? onFinish;
    20. CombineExecutor({this.onStart, this.onFinish});
    21. _executor(GroupKey key) {
    22. Executor executor = Executor(key);
    23. if (!_executors.contains(executor)) {
    24. _executors.add(executor);
    25. onStart?.call(key);
    26. executor.start(callback: (key) {
    27. List combines = _getCombines(key);
    28. bool flag = true;
    29. for (Monitor combineMonitor in combines) {
    30. if (!combineMonitor.isFinish() && !combineMonitor.isError()) {
    31. flag = false;
    32. break;
    33. }
    34. }
    35. //表示最后一个都已执行完成
    36. if (flag) {
    37. executor.stop(callback: (key) {
    38. onFinish?.call(key);
    39. _clearCombine(key);
    40. _executors.remove(executor);
    41. });
    42. }
    43. });
    44. }
    45. }
    46. ///停止,在退出界面时调用
    47. stop() {
    48. for (Executor executor in _executors) {
    49. executor.stop();
    50. }
    51. _executors.clear();
    52. _clearAllCombine();
    53. }
    54. ///获取合并执行观察者,
    55. ///设置到请求逻辑中。
    56. Monitor getCombine(GroupKey key) {
    57. Monitor combineMonitor = Monitor();
    58. _addCombine(key, combineMonitor);
    59. _executor(key);
    60. return combineMonitor;
    61. }
    62. ///新增一个CombineMonitor
    63. _addCombine(GroupKey key, Monitor combine) {
    64. if (key.isMonitor) {
    65. if (_combines.containsKey(key)) {
    66. List? combines = _combines[key];
    67. combines ??= [];
    68. if (!combines.contains(combine)) {
    69. combines.add(combine);
    70. }
    71. } else {
    72. _combines.putIfAbsent(key, () => [combine]);
    73. }
    74. }
    75. }
    76. List _getCombines(GroupKey key) {
    77. if (_isEmptyCombine(key)) {
    78. return [];
    79. } else {
    80. return _combines[key]!;
    81. }
    82. }
    83. ///CombineMonitor是否为空
    84. _isEmptyCombine(GroupKey key) {
    85. return !_combines.containsKey(key) || _combines[key].isNullOrEmpty;
    86. }
    87. _clearCombine(GroupKey key) {
    88. _combines.remove(key);
    89. }
    90. ///清除全部的CombineMonitor
    91. _clearAllCombine() {
    92. _combines.clear();
    93. }
    94. }
    95. ///测试
    96. class Test {
    97. test() {
    98. ///创建一个GroupKey,改key可用于一组需要调用的接口上
    99. GroupKey groupKey = GroupKey();
    100. ///创建对象
    101. CombineExecutor executor = CombineExecutor(
    102. onStart: (key) {
    103. ///print("执行了onStart");
    104. },
    105. onFinish: (key) {
    106. if (key == groupKey) {
    107. ///print("执行了onFinish");
    108. }
    109. },
    110. );
    111. ///获取CombineMonitor 传入到接口调用中
    112. Monitor monitor = executor.getCombine(groupKey);
    113. ///模拟异步对Monitor进行操作
    114. Future.delayed(const Duration(seconds: 2), () {
    115. monitor.onFinish();
    116. });
    117. ///退出界面
    118. executor.stop();
    119. }
    120. }

    3.使用

  • 相关阅读:
    日常中msvcp71.dll丢失怎样修复?分享5个修复方法
    Js基础——事件流
    银河麒麟服务器系统使用的一些问题和解决方案
    【JavaSE】类与对象
    使用HBuilderX将vue或H5项目打包app
    用CMake编译项目 & CMake和g++的区别
    【webrtc】初始mia
    【Kali安全渗透测试实践教程】第8章 Web渗透
    Python系列-Django
    一键重装win7系统详细教程
  • 原文地址:https://blog.csdn.net/u012800952/article/details/132695791