Flutter 异步与同步(3):Completer 详解
一、什么是 Completer?
Completer 是 Dart 异步库 dart:async 中的一个类,用于创建和控制一个 Future。它允许开发者手动完成一个 Future,使得 Future 的完成时机可以由代码逻辑自由控制,而不是由某个异步操作自动决定。
简单说,Completer 是 Future 的“控制器”。
二、Completer 基本概念
(1)核心作用
Completer 充当 Future 的控制器,可以:
- 手动创建 Future
- 在任意时机完成 Future(成功/失败)
- 将回调式 API 转换为 Future 式 API
(2)核心方法
| 方法 | 说明 |
|---|---|
complete(value) |
以成功状态完成 Future,并返回结果值 |
completeError(e) |
以失败状态完成 Future,抛出异常 |
future |
获取 Completer 控制的 Future 对象 |
三、基本使用示例
(1)创建并完成 Future
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
printMessage();
}
Future<String> createDelayedMessage() {
final completer = Completer<String>();
// 模拟异步操作
Timer(const Duration(seconds: 2), () {
completer.complete('异步操作完成');
});
return completer.future;
}
// 使用
void printMessage() async {
final message = await createDelayedMessage();
debugPrint(message); // 2秒后打印"异步操作完成"
}
2秒后输出打印:
flutter: 异步操作完成
(2)错误处理
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
calculate();
}
Future<int> divide(int a, int b) {
final completer = Completer<int>();
if (b == 0) {
completer.completeError(ArgumentError('除数不能为0'));
} else {
completer.complete(a ~/ b);
}
return completer.future;
}
// 使用
void calculate() async {
try {
final result = await divide(10, 2);
debugPrint(result as String?); // 5
await divide(10, 0);
} catch (e) {
debugPrint(e as String?); // 打印错误: 除数不能为0
}
}
2秒后输出打印:
flutter: 5
flutter: Invalid argument(s): 除数不能为0
四、实际应用场景
4.1 自定义异步操作
Future<String> loadData() {
Completer<String> completer = Completer();
// 假设是一些原生代码回调,或事件监听
someAsyncEvent((result) {
completer.complete(result);
}, (error) {
completer.completeError(error);
});
return completer.future;
}
4.1 将回调转换为 Future
// 原始回调式API
class LegacyAPI {
void fetchData(void Function(String) callback) {
Timer(const Duration(seconds: 1), () => callback('数据结果'));
}
}
// 使用Completer包装为Future
Future<String> fetchDataAsFuture() {
final completer = Completer<String>();
LegacyAPI().fetchData((result) {
completer.complete(result);
});
return completer.future;
}
// 使用
void useNewAPI() async {
final data = await fetchDataAsFuture();
print(data); // "数据结果"
}
4.3 多个异步操作协同
Future<String> waitForFirstSuccess(List<String> urls) {
final completer = Completer<String>();
for (final url in urls) {
http.get(Uri.parse(url)).then((response) {
if (!completer.isCompleted && response.statusCode == 200) {
completer.complete(response.body);
}
}).catchError((_) {});
}
// 设置超时
Timer(Duration(seconds: 10), () {
if (!completer.isCompleted) {
completer.completeError(TimeoutException('所有请求超时'));
}
});
return completer.future;
}
4.4 结合 Timer 实现超时机制
Future<String> fetchDataWithTimeout() {
Completer<String> completer = Completer();
Timer timer = Timer(Duration(seconds: 5), () {
if (!completer.isCompleted) {
completer.completeError(TimeoutException("请求超时"));
}
});
someAsyncFetch((result) {
if (!completer.isCompleted) {
completer.complete(result);
timer.cancel();
}
}, (error) {
if (!completer.isCompleted) {
completer.completeError(error);
timer.cancel();
}
});
return completer.future;
}
五、注意事项
(1)完成状态检查
if (!completer.isCompleted) {
completer.complete(value);
}
(2)内存泄漏
- 确保 Completer 最终会被完成
- 避免持有不再需要的 Completer 引用
(3)单次使用原则
- 每个 Completer 只能完成一次
- 重复调用 complete/completeError 会抛出 StateError
(4)Zone 处理
runZonedGuarded(() {
final completer = Completer();
// 异步操作
}, (error, stack) {
if (!completer.isCompleted) {
completer.completeError(error, stack);
}
});
六、与普通 Future 对比
| 特性 | Completer | 普通 Future |
|---|---|---|
| 控制权 | 手动控制完成时机 | 由异步操作自动控制 |
| 创建方式 | 显式构造 | 通过 async 函数或 Future 构造函数 |
| 使用场景 | 需要手动控制的异步流程 | 常规异步操作 |
| 灵活性 | 高 | 低 |
| 代码复杂度 | 较高 | 较低 |
Completer 为 Flutter 开发提供了更底层的 Future 控制能力,合理使用可以解决许多复杂的异步编程问题,但也要注意避免滥用导致代码难以维护。
参考:
Flutter 中的 Completer 详解:异步编程的利器Flutter 和 Dart 语言中,异步编程无处不在。F - 掘金

浙公网安备 33010602011771号