前言:
这一讲对高性能需求是很重要的,响应式,异步,等,都是能够提升性能的手段,不过很多时候还是平铺直述,大力出奇迹才是正道。
一、总览
本讲聚焦 Flutter 中异步编程的核心技术栈,解决「UI 构建依赖异步数据(如网络请求、文件读取、延时操作)」的核心问题:
- 基础层:掌握
Future、async/await处理单次异步任务(如一次网络请求); - UI 层:通过
FutureBuilder、StreamBuilder将异步任务状态与 UI 联动,避免手动管理「加载中/成功/失败」状态; - 体验层:结合
LinearProgressIndicator/CircularProgressIndicator实现异步过程的可视化反馈; - 核心目标:让你从「手动维护异步状态+更新UI」的繁琐逻辑中解放,用 Flutter 内置组件优雅处理异步场景。
再来一遍:
- 异步基础 :
Future处理单次异步任务,async/await简化异步代码,需用try/catch捕获异常; - 异步构建 :
FutureBuilder绑定单次异步任务,StreamBuilder绑定持续数据流,核心是根据AsyncSnapshot的状态(connectionState/hasError/hasData)构建UI; - 状态与反馈 :异步场景需覆盖「loading(进度条)、error(重试)、success(数据展示)」三状态,且需注意缓存
Future、关闭StreamController避免内存泄漏。

原理解读
- 异步任务源:所有需要耗时的操作(网络、文件、设备传感器等)是异步的起点;
- Future/Stream :Flutter 封装的异步数据载体(
Future对应「单次结果」,Stream对应「持续数据流」); - async/await:简化异步代码的语法糖,替代回调地狱,让异步代码像同步代码一样易读;
- 异步构建器 :
FutureBuilder/StreamBuilder监听异步任务状态,自动触发 UI 重建; - 三状态管理:异步任务的通用生命周期(加载中→成功/失败),是异步 UI 构建的核心逻辑;
- 进度指示器:可视化异步状态,提升用户体验。
二、核心技术拆解
2.1 异步基础:Future、async/await
核心概念
Future:表示「未来某个时间会完成的操作」,有三种状态:未完成(pending)、完成成功(completed with value)、完成失败(completed with error);async:标记函数为异步函数,返回值自动包装为Future;await:暂停异步函数执行,直到Future完成,只能在async函数中使用。
基础案例
dart
// 模拟异步任务:延时获取数据
Future<String> fetchData() async {
// 模拟网络请求延时2秒
await Future.delayed(const Duration(seconds: 2));
// 可注释下面一行,取消抛出异常,测试error状态
// throw Exception("网络请求失败:服务器无响应");
return "异步数据加载成功!";
}
// 调用异步函数的示例
void testAsync() async {
print("开始执行异步任务...");
try {
String result = await fetchData();
print("结果:$result");
} catch (e) {
print("异常:$e");
}
}
注意事项
async函数即使没有显式返回Future,也会自动包装返回值(如async () => 1等价于() => Future.value(1));- 未处理的
Future异常会导致应用崩溃,必须用try/catch捕获,或通过Future.catchError()处理; await只能在async函数内使用,不能在main函数(非 async)直接使用(需套main() async {})。
2.2 异步构建:FutureBuilder
核心作用
将 Future 与 UI 绑定,根据 Future 的状态(loading/error/success)自动重建 UI,无需手动调用 setState。
核心属性
| 属性名 | 类型 | 作用 |
|---|---|---|
future |
Future<T>? |
要监听的异步任务(注意:每次build会重新创建Future,需用变量缓存) |
builder |
Widget Function(BuildContext, AsyncSnapshot<T>) |
根据异步状态构建UI的回调 |
initialData |
T? |
初始数据(可选,未加载完成时显示) |
基础案例
php
class FutureBuilderDemo extends StatelessWidget {
// 缓存Future,避免每次build重新创建
final Future<String> _future = fetchData();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("FutureBuilder 示例")),
body: Center(
child: FutureBuilder<String>(
future: _future,
builder: (context, snapshot) {
// 1. 加载中状态:ConnectionState.waiting
if (snapshot.connectionState == ConnectionState.waiting) {
return const Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 圆形进度条
CircularProgressIndicator(),
SizedBox(height: 16),
Text("加载中...请稍候")
],
);
}
// 2. 错误状态:hasError为true
else if (snapshot.hasError) {
return Text(
"加载失败:${snapshot.error}",
style: const TextStyle(color: Colors.red, fontSize: 18),
);
}
// 3. 成功状态:hasData为true
else if (snapshot.hasData) {
return Text(
snapshot.data!,
style: const TextStyle(color: Colors.green, fontSize: 20),
);
}
// 其他状态(兜底)
else {
return const Text("暂无数据");
}
},
),
),
);
}
}
注意事项
- 避免Future重建 :不要在
future属性中直接写fetchData()(每次build都会重新执行异步任务),需提前缓存为变量; - ConnectionState判断 :
ConnectionState.waiting是加载中,done表示任务完成(需再判断hasError/hasData); - 内存泄漏 :如果页面销毁时异步任务还未完成,需手动取消(如用
cancelable_future库)。
2.3 异步构建:StreamBuilder
核心作用
监听 Stream(持续数据流),实时更新 UI(如实时聊天消息、倒计时、传感器数据),比 FutureBuilder 多「持续接收数据」的能力。
核心概念
Stream:数据流,可多次发射数据/错误/完成信号;StreamController:创建和管理Stream的控制器(需手动关闭避免内存泄漏);StreamBuilder:绑定Stream,实时监听数据变化并重建 UI。
核心属性
| 属性名 | 类型 | 作用 |
|---|---|---|
stream |
Stream<T>? |
要监听的数据流 |
builder |
Widget Function(BuildContext, AsyncSnapshot<T>) |
实时构建UI的回调 |
initialData |
T? |
初始数据 |
基础案例(倒计时示例)
less
class StreamBuilderDemo extends StatefulWidget {
@override
_StreamBuilderDemoState createState() => _StreamBuilderDemoState();
}
class _StreamBuilderDemoState extends State<StreamBuilderDemo> {
late StreamController<int> _streamController;
late Stream<int> _countdownStream;
@override
void initState() {
super.initState();
// 1. 创建Stream控制器
_streamController = StreamController<int>();
// 2. 生成倒计时数据流(从10到0)
_countdownStream = Stream.periodic(
const Duration(seconds: 1), // 每隔1秒发射一次数据
(count) => 10 - count, // 计算倒计时数值
).take(11); // 只取11次(0-10)
// 3. 将数据流添加到控制器
_countdownStream.listen(
(value) {
_streamController.add(value);
// 倒计时结束关闭控制器
if (value == 0) _streamController.close();
},
onError: (e) => _streamController.addError(e),
onDone: () => print("倒计时结束"),
);
}
@override
void dispose() {
// 必须关闭控制器,避免内存泄漏
_streamController.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("StreamBuilder 示例")),
body: Center(
child: StreamBuilder<int>(
stream: _streamController.stream,
initialData: 10, // 初始值
builder: (context, snapshot) {
// 加载中/正常状态
if (snapshot.connectionState == ConnectionState.active ||
snapshot.connectionState == ConnectionState.waiting) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 线性进度条(根据倒计时进度更新)
LinearProgressIndicator(
value: snapshot.data! / 10, // 进度0-1
minHeight: 8,
backgroundColor: Colors.grey[200],
color: Colors.blue,
),
const SizedBox(height: 20),
Text(
"倒计时:${snapshot.data}秒",
style: const TextStyle(fontSize: 24),
),
],
);
}
// 错误状态
else if (snapshot.hasError) {
return Text(
"错误:${snapshot.error}",
style: const TextStyle(color: Colors.red, fontSize: 18),
);
}
// 完成状态(倒计时结束)
else {
return const Text(
"倒计时结束!",
style: TextStyle(color: Colors.green, fontSize: 28),
);
}
},
),
),
);
}
}
注意事项
StreamController必须在dispose中关闭(close()),否则会导致内存泄漏;StreamBuilder会监听整个数据流生命周期,直到Stream关闭或页面销毁;- 常用
Stream生成方式:Stream.periodic()(定时发射)、Stream.fromIterable()(从集合生成)、StreamController(手动发射)。
2.4 进度条:Linear/CircularProgressIndicator
核心作用
可视化异步任务的进度,分为「确定进度」和「不确定进度」两种模式:
- 不确定模式(默认):无限循环动画,用于未知耗时的任务(如网络请求);
- 确定模式:设置
value(0-1),用于已知进度的任务(如文件下载)。
核心属性(通用)
| 属性名 | 类型 | 作用 |
|---|---|---|
value |
double? |
进度值(0-1,null为不确定模式) |
color |
Color? |
进度条颜色 |
backgroundColor |
Color? |
背景颜色(仅确定模式) |
strokeWidth |
double |
进度条宽度(Circular专属) |
minHeight |
double |
进度条高度(Linear专属) |
基础案例
less
// 不确定进度条(网络请求加载中)
const CircularProgressIndicator(
color: Colors.blue,
strokeWidth: 4,
);
// 确定进度条(文件下载,进度50%)
LinearProgressIndicator(
value: 0.5,
minHeight: 8,
color: Colors.green,
backgroundColor: Colors.grey[200],
);
三、综合应用案例
需求说明
实现一个「用户信息加载页面」:
- 进入页面后显示「圆形进度条+加载中文字」;
- 模拟网络请求加载用户信息(延时2秒);
- 加载成功:显示用户头像、名称、简介(用LinearProgressIndicator展示加载完成度);
- 加载失败:显示错误提示+重试按钮;
- 额外实现一个实时刷新的「数据更新倒计时」(StreamBuilder)。
完整代码
less
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '异步操作综合案例',
theme: ThemeData(primarySwatch: Colors.blue),
home: const AsyncComprehensiveDemo(),
);
}
}
// 模拟用户数据模型
class User {
final String name;
final String avatar;
final String desc;
User({required this.name, required this.avatar, required this.desc});
}
// 模拟异步请求:加载用户信息
Future<User> fetchUserInfo() async {
await Future.delayed(const Duration(seconds: 2));
// 注释下面一行,测试成功状态;取消注释,测试错误状态
// throw Exception("加载失败:网络超时");
return User(
name: "Flutter开发者",
avatar: "https://img.icons8.com/fluency/96/000000/user.png",
desc: "专注Flutter异步编程与UI构建",
);
}
// 综合案例页面
class AsyncComprehensiveDemo extends StatefulWidget {
const AsyncComprehensiveDemo({super.key});
@override
_AsyncComprehensiveDemoState createState() => _AsyncComprehensiveDemoState();
}
class _AsyncComprehensiveDemoState extends State<AsyncComprehensiveDemo> {
late Future<User> _userFuture;
late StreamController<int> _refreshController;
@override
void initState() {
super.initState();
// 初始化异步任务
_userFuture = fetchUserInfo();
// 初始化刷新倒计时Stream(10秒后自动刷新)
_refreshController = StreamController<int>();
Stream.periodic(const Duration(seconds: 1), (count) => 10 - count)
.take(11)
.listen(
(value) => _refreshController.add(value),
onDone: () => _refreshController.close(),
);
}
// 重试加载用户信息
void _reloadUserInfo() {
setState(() {
_userFuture = fetchUserInfo();
});
}
@override
void dispose() {
_refreshController.close(); // 关闭Stream控制器
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("异步综合案例"),
actions: [
// StreamBuilder:实时刷新倒计时
StreamBuilder<int>(
stream: _refreshController.stream,
initialData: 10,
builder: (context, snapshot) {
if (snapshot.data == 0) {
return TextButton(
onPressed: _reloadUserInfo,
child: const Text("立即刷新", style: TextStyle(color: Colors.white)),
);
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Center(
child: Text(
"${snapshot.data}秒后刷新",
style: const TextStyle(color: Colors.white, fontSize: 12),
),
),
);
},
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: FutureBuilder<User>(
future: _userFuture,
builder: (context, snapshot) {
// 1. 加载中状态
if (snapshot.connectionState == ConnectionState.waiting) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircularProgressIndicator(
color: Colors.blue,
strokeWidth: 6,
),
const SizedBox(height: 20),
const Text("正在加载用户信息..."),
const SizedBox(height: 10),
// 线性进度条(不确定模式)
const LinearProgressIndicator(
color: Colors.blue,
minHeight: 4,
),
],
);
}
// 2. 错误状态
if (snapshot.hasError) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 64),
const SizedBox(height: 20),
Text(
"加载失败:${snapshot.error}",
style: const TextStyle(color: Colors.red, fontSize: 16),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _reloadUserInfo,
child: const Text("重试加载"),
),
],
);
}
// 3. 成功状态
final user = snapshot.data!;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 线性进度条(确定模式,100%完成)
LinearProgressIndicator(
value: 1.0,
minHeight: 4,
color: Colors.green,
backgroundColor: Colors.grey[200],
),
const SizedBox(height: 30),
// 用户头像
CircleAvatar(
backgroundImage: NetworkImage(user.avatar),
radius: 64,
),
const SizedBox(height: 20),
// 用户名
Text(
user.name,
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
// 用户简介
Text(
user.desc,
style: const TextStyle(fontSize: 16, color: Colors.grey),
),
],
);
},
),
),
);
}
}

效果说明
-
页面启动后,显示「圆形进度条+线性进度条(不确定)+加载中文字」;
-
2秒后:
- 成功:显示用户头像、名称、简介,线性进度条变为100%(绿色);
- 失败:显示错误图标、提示文字、重试按钮;
-
右上角有「10秒倒计时」(StreamBuilder实现),倒计时结束后显示「立即刷新」按钮,点击可重新加载数据;
-
所有异步状态(loading/error/success)均有对应的UI反馈,符合用户体验最佳实践。
关键注意事项
- 避免在
FutureBuilder的future属性中直接创建Future(会重复执行); StreamController必须在dispose中关闭;- 所有异步异常必须处理,否则会导致应用崩溃;
- 进度条分「确定/不确定」模式,按需选择(网络请求用不确定,文件下载用确定)。