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
List> _monitors = {}; -
- ///Executor 保存
- final List
_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
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
? combines = _monitors[key]; - combines ??= [];
- if (!combines.contains(combine)) {
- combines.add(combine);
- }
- } else {
- _monitors.putIfAbsent(key, () => [combine]);
- }
- }
- }
-
- List
_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.使用
