本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
Completer是Dart/Flutter中用于手动控制Future完成时机的类。它允许将一个异步操作的结果"承诺"(Future)与完成该承诺的控制权分离开来。
-
Future:一个将在未来某个时间点返回结果或错误的承诺
-
Completer:控制Future何时完成的"控制器"
-
Future vs Completer:
-
Future是"被承诺者"(被动等待结果)
-
Completer是"承诺者"(主动决定何时完成)
-
二、基本结构
import 'dart:async';
void main() async {
// 1. 创建Completer
Completer<String> completer = Completer<String>();
// 2. 获取对应的Future
Future<String> future = completer.future;
// 3. 监听Future的结果
future.then((value) {
print('Future完成,结果: $value');
}).catchError((error) {
print('Future出错: $error');
});
// 4. 模拟异步操作后完成Completer
Future.delayed(Duration(seconds: 2), () {
// 完成Future并传递结果
completer.complete('操作成功!');
// 或者如果出错:
// completer.completeError('操作失败');
});
}
三、Completer主要方法
1. complete(value) - 成功完成Future
Completer<int> completer = Completer<int>();
completer.complete(42); // Future将返回42
2. completeError(error, [stackTrace]) - 以错误完成Future
Completer<String> completer = Completer<String>();
completer.completeError(Exception('操作失败'));
3. future - 获取对应的Future对象
Future<String> myFuture = completer.future;
4. isCompleted - 检查是否已完成
if (!completer.isCompleted) {
completer.complete('现在完成');
}
四、实际应用
1:将回调函数转换为Future(最常用)
import 'dart:async';
// 传统回调函数
void fetchDataWithCallback(Function(String) callback) {
// 模拟网络请求
Future.delayed(Duration(seconds: 1), () {
callback('数据加载完成');
});
}
// 使用Completer转换为Future
Future<String> fetchDataAsFuture() {
Completer<String> completer = Completer<String>();
fetchDataWithCallback((result) {
if (result.contains('完成')) {
completer.complete(result);
} else {
completer.completeError(Exception('数据加载失败'));
}
});
return completer.future;
}
// 使用方式
void useFuture() async {
try {
String result = await fetchDataAsFuture();
print('结果: $result');
} catch (e) {
print('错误: $e');
}
}
2:手动控制多个异步操作的完成
Future<List<String>> fetchMultipleResources() {
Completer<List<String>> completer = Completer<List<String>>();
List<String> results = [];
int completedCount = 0;
const totalTasks = 3;
// 模拟多个异步任务
for (int i = 0; i < totalTasks; i++) {
Future.delayed(Duration(seconds: i + 1), () async {
// 模拟获取数据
String data = await fetchItem(i);
results.add(data);
completedCount++;
// 所有任务完成后完成Completer
if (completedCount == totalTasks) {
completer.complete(results);
}
});
}
return completer.future;
}
Future<String> fetchItem(int index) async {
await Future.delayed(Duration(milliseconds: 500));
return '项目 $index 数据';
}
3:超时控制
Future<String> fetchWithTimeout(Duration timeout) {
Completer<String> completer = Completer<String>();
// 开始实际的数据获取
startFetching().then((value) {
if (!completer.isCompleted) {
completer.complete(value);
}
}).catchError((error) {
if (!completer.isCompleted) {
completer.completeError(error);
}
});
// 设置超时
Future.delayed(timeout, () {
if (!completer.isCompleted) {
completer.completeError(
TimeoutException('操作超时', timeout)
);
}
});
return completer.future;
}
4:状态管理
class AuthenticationService {
Completer<void> _loginCompleter;
Future<void> login(String username, String password) {
_loginCompleter = Completer<void>();
// 模拟登录请求
_performLogin(username, password);
return _loginCompleter.future;
}
void _performLogin(String username, String password) {
// 模拟网络请求
Future.delayed(Duration(seconds: 2), () {
if (username == 'admin' && password == '123456') {
_loginCompleter?.complete();
} else {
_loginCompleter?.completeError(Exception('登录失败'));
}
_loginCompleter = null;
});
}
void cancelLogin() {
if (_loginCompleter != null && !_loginCompleter.isCompleted) {
_loginCompleter.completeError(CancelledException('用户取消'));
_loginCompleter = null;
}
}
}
五、Completer的替代方案
1. 使用StreamController
// 当需要多个值时,使用StreamController更合适
StreamController<String> controller = StreamController<String>();
Stream<String> stream = controller.stream;
controller.add('值1');
controller.add('值2');
controller.close();
2. 直接返回Future
// 如果可以,尽量使用async/await直接创建Future
Future<String> simpleFuture() async {
await Future.delayed(Duration(seconds: 1));
return '完成';
}
476

被折叠的 条评论
为什么被折叠?



