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 卡顿。

异步编程的意义:让程序在"等待"的同时继续渲染界面。

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:协调调度顺序;

  • 搭配 FutureBuilderStreamBuilder

    就能构建不卡顿、响应流畅的 Flutter 界面。

相关推荐
曹牧3 小时前
C# 中的 DateTime.Now.ToString() 方法支持多种预定义的格式字符
前端·c#
勿在浮沙筑高台3 小时前
海龟交易系统R
前端·人工智能·r语言
歪歪1003 小时前
C#如何在数据可视化工具中进行数据筛选?
开发语言·前端·信息可视化·前端框架·c#·visual studio
alexhilton4 小时前
Compose CameraX现已稳定:给Composer的端到端指南
android·kotlin·android jetpack
星释4 小时前
鸿蒙Flutter三方库适配指南-02.Flutter相关知识基础
flutter·华为·harmonyos
Captaincc4 小时前
AI 能帮你写代码,但把代码变成软件,还是得靠人
前端·后端·程序员
吃饺子不吃馅6 小时前
如何设计一个 Canvas 事件系统?
前端·canvas·图形学
阿里云云原生6 小时前
移动端性能监控探索:可观测 Android 采集探针架构与实现
android
雨白6 小时前
玩转 Flow 操作符(一):数据转换与过滤
android·kotlin