Flutter 异步编程:Future 与 Stream 深度解析
系列入口:
1️⃣ Future 与 Stream 深度解析
2️⃣Isolate 与 compute 性能优化
3️⃣ FutureBuilder 与 StreamBuilder 架构优化
4️⃣ 异步 + 状态管理融合(Riverpod / Bloc)
5️⃣ Flutter 响应式架构设计
欢迎留言 👍 点个 关注 ❤️,不错过后续更新!
引言
在 Flutter 开发中,异步编程无处不在——从网络请求到动画控制、文件读写到 Socket 通信。
而支撑这一切的核心机制,就是 Future 与 Stream。
本文将结合项目实战,从原理到最佳实践,一次性搞懂 Flutter 的异步体系。
一、为什么 Flutter 需要异步?
Flutter 采用 单线程 UI 渲染模型。
主 Isolate 负责所有渲染与事件响应,如果执行耗时任务(如 I/O 或 JSON 解析)会造成 UI 卡顿。
异步编程的意义:让程序在“等待”的同时继续渲染界面。
void fetchData() {final data = http.get('https://api.example.com/user');print('请求已发送');
}
这时 print 会先执行,因为 Dart 的事件循环会让 Future 异步排队执行。
二、Future:一次性异步任务
Future 表示一个将来会返回结果的异步操作。它可以成功、失败或超时。
Future<String> getUserName() async {await Future.delayed(const Duration(seconds: 2));return 'FlutterDev';
}void main() async {print('开始');final name = await getUserName();print('你好,$name');
}
输出:
开始
(等待2秒)
你好,FlutterDev
三、async / await 实战与最佳实践
1. async + await 原理速记
-
async把函数变成异步函数,返回Future<T>; -
await会暂停当前函数直到该Future完成; -
await后续代码会被放入 microtask 队列,优先执行。
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 并行
// 串行(前一步结果是后一步输入)
final token = await login();
final profile = await fetchProfile(token);// 并行(互不依赖)
final result = await Future.wait([apiA(), apiB(), apiC()]);
3. 错误与超时
try {final data = await fetch();
} on TimeoutException {print('请求超时');
} catch (e, st) {print('异常: $e');
}
4. 重试与竞速
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
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 无法直接取消,可用软标志:
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。
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 → 下一帧
示例:
print('A');
scheduleMicrotask(() => print('B'));
Future(() => print('C'));
print('D');
// 输出: A, D, B, C
七、实战案例:下载进度条
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 界面。
