系列入口:
3️⃣ FutureBuilder 与 StreamBuilder 架构优化
4️⃣ 异步 + 状态管理融合(Riverpod / Bloc)
5️⃣ Flutter 响应式架构设计
欢迎留言 👍 点个 关注 ❤️,不错过后续更新!
引言
在 Flutter 开发中,异步编程无处不在------从网络请求到动画控制、文件读写到 Socket 通信。
而支撑这一切的核心机制,就是 Future 与 Stream。
本文将结合项目实战,从原理到最佳实践,一次性搞懂 Flutter 的异步体系。
一、为什么 Flutter 需要异步?
Flutter 采用 单线程 UI 渲染模型 。
主 Isolate 负责所有渲染与事件响应,如果执行耗时任务(如 I/O 或 JSON 解析)会造成 UI 卡顿。
异步编程的意义:让程序在"等待"的同时继续渲染界面。
Kotlin
void fetchData() {
final data = http.get('https://api.example.com/user');
print('请求已发送');
}
这时 print 会先执行,因为 Dart 的事件循环会让 Future 异步排队执行。
二、Future:一次性异步任务
Future 表示一个将来会返回结果的异步操作。它可以成功、失败或超时。
Kotlin
Future<String> getUserName() async {
await Future.delayed(const Duration(seconds: 2));
return 'FlutterDev';
}
void main() async {
print('开始');
final name = await getUserName();
print('你好,$name');
}
输出:
Kotlin
开始
(等待2秒)
你好,FlutterDev
三、async / await 实战与最佳实践
1. async + await 原理速记
-
async把函数变成异步函数,返回Future<T>; -
await会暂停当前函数 直到该Future完成; -
await后续代码会被放入 microtask 队列,优先执行。
Kotlin
Future<User> fetchUser() async {
final res = await http.get(Uri.parse('https://api.xxx.com/user'));
return User.fromJson(json.decode(res.body));
}
2. 串行 vs 并行
Kotlin
// 串行(前一步结果是后一步输入)
final token = await login();
final profile = await fetchProfile(token);
// 并行(互不依赖)
final result = await Future.wait([apiA(), apiB(), apiC()]);
3. 错误与超时
Kotlin
try {
final data = await fetch();
} on TimeoutException {
print('请求超时');
} catch (e, st) {
print('异常: $e');
}
4. 重试与竞速
Kotlin
Future<T> retry<T>(Future<T> Function() run, {int max = 3}) async {
var delay = const Duration(milliseconds: 300);
for (int i = 0; i < max; i++) {
try { return await run(); } catch (_) {}
await Future.delayed(delay);
delay *= 2; // 指数退避
}
return await run();
}
// 竞速:谁先返回用谁
final fastest = await Future.any([pingA(), pingB()]);
5. UI绑定:FutureBuilder
Kotlin
FutureBuilder<User>(
future: fetchUser(),
builder: (_, snap) {
if (snap.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snap.hasError) return Text('错误:${snap.error}');
return Text('Hi, ${snap.data!.name}');
},
);
6. 异步取消
Dart 的 Future 无法直接取消,可用软标志:
Kotlin
bool _canceled = false;
Future<void> runJob() async {
_canceled = false;
final a = await step1();
if (_canceled) return;
final b = await step2(a);
}
void cancelJob() => _canceled = true;
或使用 CancelableOperation(来自 package:async)。
7. 小结口诀
有依赖 → 串行;无依赖 → 并行;
操作UI前先判断
mounted;超时、重试、竞速都靠 Future 组合。
四、Stream:持续事件的流
Stream 用于处理多次异步事件,如进度更新、传感器、Socket。
Kotlin
final controller = StreamController<int>();
controller.stream.listen(
(event) => print('收到:$event'),
onError: (e) => print('错误:$e'),
onDone: () => print('结束'),
);
controller.add(1);
controller.add(2);
controller.close();
输出:
收到:1
收到:2
结束
常见应用场景
| 场景 | 示例 |
|---|---|
| 下载/上传进度 | Stream<double> |
| 蓝牙 / 串口数据 | Stream<List<int>> |
| 用户输入防抖 | debounce |
| Socket 长连接 | Stream<String> |
五、Future vs Stream 对比
| 特性 | Future | Stream |
|---|---|---|
| 结果数量 | 一次 | 多次 |
| 典型场景 | 网络请求 | 进度/Socket |
| 取消支持 | 无 | 可取消订阅 |
| UI绑定组件 | FutureBuilder | StreamBuilder |
六、Event Loop 与微任务机制
Dart 异步执行顺序:
microtask → event → render → 下一帧
示例:
Kotlin
print('A');
scheduleMicrotask(() => print('B'));
Future(() => print('C'));
print('D');
// 输出: A, D, B, C
七、实战案例:下载进度条
Kotlin
class DownloadTask {
final _ctrl = StreamController<double>();
Stream<double> get progress => _ctrl.stream;
Future<void> start() async {
for (int i = 1; i <= 10; i++) {
await Future.delayed(const Duration(milliseconds: 500));
_ctrl.add(i / 10);
}
_ctrl.close();
}
}
final task = DownloadTask();
task.progress.listen((p) => print('进度: ${(p * 100).toInt()}%'));
task.start();
八、异步任务选型决策表
| 场景 | 推荐方案 |
|---|---|
| 一次性请求(接口 / 文件) | Future + async/await |
| 多次更新(进度 / 实时数据) | Stream |
| 并发请求 | Future.wait / Future.any |
| 可取消任务 | CancelableOperation |
| 大计算任务 | compute / Isolate |
| UI绑定 | FutureBuilder / StreamBuilder |
九、总结
Future:一次性异步操作;
Stream:多次事件流;
async/await:让异步像同步;
Event Loop:协调调度顺序;
搭配
FutureBuilder与StreamBuilder,就能构建不卡顿、响应流畅的 Flutter 界面。