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